From 03171381ab0af37bc93223cdc9ed71cc2e6dced2 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Fri, 6 Mar 2026 23:19:22 -0800 Subject: [PATCH 01/10] drafting nvidia-nat-benchmarks subpackage Signed-off-by: Bryan Bednarski --- .../benchmarks/agent_leaderboard/README.md | 188 ++++++++++++ examples/benchmarks/agent_leaderboard/configs | 1 + .../agent_leaderboard/pyproject.toml | 31 ++ .../__init__.py | 3 + .../configs/eval_all_domains.yml | 42 +++ .../configs/eval_banking.yml | 38 +++ .../register.py | 4 + examples/benchmarks/bfcl/README.md | 178 ++++++++++++ examples/benchmarks/bfcl/configs | 1 + examples/benchmarks/bfcl/pyproject.toml | 30 ++ .../bfcl/src/nat_benchmark_bfcl/__init__.py | 3 + .../configs/eval_ast_simple.yml | 35 +++ .../configs/eval_fc_simple.yml | 35 +++ .../configs/eval_react_simple.yml | 36 +++ .../bfcl/src/nat_benchmark_bfcl/register.py | 4 + examples/benchmarks/byob/README.md | 199 +++++++++++++ examples/benchmarks/byob/configs | 1 + examples/benchmarks/byob/pyproject.toml | 31 ++ .../byob/src/nat_benchmark_byob/__init__.py | 3 + .../configs/eval_exact_match.yml | 41 +++ .../byob/src/nat_benchmark_byob/register.py | 4 + examples/benchmarks/tooltalk/README.md | 191 ++++++++++++ examples/benchmarks/tooltalk/configs | 1 + examples/benchmarks/tooltalk/pyproject.toml | 30 ++ .../src/nat_benchmark_tooltalk/__init__.py | 3 + .../configs/eval_easy.yml | 37 +++ .../src/nat_benchmark_tooltalk/register.py | 4 + .../configs/agent_leaderboard_eval.yaml | 46 +++ .../configs/bfcl_ast_eval.yaml | 39 +++ .../configs/tooltalk_eval.yaml | 42 +++ packages/nvidia_nat_benchmarks/pyproject.toml | 82 ++++++ .../src/nat/plugins/benchmarks/__init__.py | 2 + .../benchmarks/agent_leaderboard/__init__.py | 2 + .../benchmarks/agent_leaderboard/config.py | 66 +++++ .../benchmarks/agent_leaderboard/dataset.py | 165 +++++++++++ .../benchmarks/agent_leaderboard/evaluator.py | 139 +++++++++ .../benchmarks/agent_leaderboard/workflow.py | 121 ++++++++ .../nat/plugins/benchmarks/bfcl/__init__.py | 2 + .../src/nat/plugins/benchmarks/bfcl/config.py | 78 +++++ .../nat/plugins/benchmarks/bfcl/dataset.py | 96 ++++++ .../nat/plugins/benchmarks/bfcl/evaluator.py | 240 +++++++++++++++ .../benchmarks/bfcl/tool_intent_stubs.py | 274 ++++++++++++++++++ .../plugins/benchmarks/bfcl/workflow_ast.py | 63 ++++ .../plugins/benchmarks/bfcl/workflow_fc.py | 106 +++++++ .../plugins/benchmarks/bfcl/workflow_react.py | 165 +++++++++++ .../nat/plugins/benchmarks/byob/__init__.py | 2 + .../src/nat/plugins/benchmarks/byob/config.py | 59 ++++ .../nat/plugins/benchmarks/byob/dataset.py | 72 +++++ .../nat/plugins/benchmarks/byob/evaluator.py | 120 ++++++++ .../src/nat/plugins/benchmarks/register.py | 25 ++ .../plugins/benchmarks/tooltalk/__init__.py | 2 + .../nat/plugins/benchmarks/tooltalk/config.py | 63 ++++ .../plugins/benchmarks/tooltalk/dataset.py | 54 ++++ .../plugins/benchmarks/tooltalk/evaluator.py | 92 ++++++ .../plugins/benchmarks/tooltalk/workflow.py | 230 +++++++++++++++ .../nvidia_nat_benchmarks/tests/__init__.py | 0 .../tests/agent_leaderboard/__init__.py | 0 .../tests/agent_leaderboard/conftest.py | 2 + .../tests/agent_leaderboard/test_dataset.py | 141 +++++++++ .../tests/agent_leaderboard/test_evaluator.py | 148 ++++++++++ .../tests/bfcl/__init__.py | 0 .../tests/bfcl/conftest.py | 22 ++ .../tests/bfcl/test_dataset.py | 109 +++++++ .../tests/bfcl/test_evaluator.py | 167 +++++++++++ .../tests/bfcl/test_integration.py | 202 +++++++++++++ .../tests/bfcl/test_regression.py | 52 ++++ .../tests/bfcl/test_tool_intent_stubs.py | 245 ++++++++++++++++ .../tests/byob/__init__.py | 0 .../tests/byob/conftest.py | 2 + .../tests/byob/fixtures/sample_benchmark.py | 32 ++ .../tests/byob/test_evaluator.py | 133 +++++++++ .../tests/byob/test_integration.py | 114 ++++++++ .../tests/tooltalk/__init__.py | 0 .../tests/tooltalk/conftest.py | 26 ++ .../tests/tooltalk/test_dataset.py | 118 ++++++++ .../tests/tooltalk/test_evaluator.py | 157 ++++++++++ .../tests/tooltalk/test_integration.py | 165 +++++++++++ .../tests/tooltalk/test_regression.py | 196 +++++++++++++ ..._per_user_function_group_eval_isolation.py | 273 +++++++++++++++++ 79 files changed, 5925 insertions(+) create mode 100644 examples/benchmarks/agent_leaderboard/README.md create mode 120000 examples/benchmarks/agent_leaderboard/configs create mode 100644 examples/benchmarks/agent_leaderboard/pyproject.toml create mode 100644 examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py create mode 100644 examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml create mode 100644 examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml create mode 100644 examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py create mode 100644 examples/benchmarks/bfcl/README.md create mode 120000 examples/benchmarks/bfcl/configs create mode 100644 examples/benchmarks/bfcl/pyproject.toml create mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py create mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml create mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml create mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml create mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py create mode 100644 examples/benchmarks/byob/README.md create mode 120000 examples/benchmarks/byob/configs create mode 100644 examples/benchmarks/byob/pyproject.toml create mode 100644 examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py create mode 100644 examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml create mode 100644 examples/benchmarks/byob/src/nat_benchmark_byob/register.py create mode 100644 examples/benchmarks/tooltalk/README.md create mode 120000 examples/benchmarks/tooltalk/configs create mode 100644 examples/benchmarks/tooltalk/pyproject.toml create mode 100644 examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py create mode 100644 examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml create mode 100644 examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py create mode 100644 packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml create mode 100644 packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml create mode 100644 packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml create mode 100644 packages/nvidia_nat_benchmarks/pyproject.toml create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py create mode 100644 packages/nvidia_nat_benchmarks/tests/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py create mode 100644 packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py create mode 100644 packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py create mode 100644 packages/nvidia_nat_benchmarks/tests/byob/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/tests/byob/conftest.py create mode 100644 packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py create mode 100644 packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/tests/byob/test_integration.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py create mode 100644 packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py diff --git a/examples/benchmarks/agent_leaderboard/README.md b/examples/benchmarks/agent_leaderboard/README.md new file mode 100644 index 0000000000..59d4696105 --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/README.md @@ -0,0 +1,188 @@ + + + +# Galileo Agent Leaderboard v2 Evaluation + +**Complexity:** 🟡 Intermediate + +Evaluate NAT agent workflows against the [Galileo Agent Leaderboard v2](https://huggingface.co/datasets/galileo-ai/agent-leaderboard-v2) benchmark. This benchmark tests whether an agent can select the correct tools for real-world use cases across multiple domains. + +## Key Features + +- **5 domains**: Banking, Healthcare, Insurance, Investment, Telecom +- **Tool stub execution**: All domain tools are registered as stubs — the agent selects tools without executing real backends +- **Tool Selection Quality (TSQ)**: F1 score between predicted and expected tool calls +- **HuggingFace integration**: Dataset downloads automatically from `galileo-ai/agent-leaderboard-v2` +- **Multi-domain evaluation**: Evaluate across one or all domains in a single run + +## Table of Contents + +- [Installation](#installation) +- [Set Up Environment](#set-up-environment) +- [Option A: Download Dataset First](#option-a-download-dataset-first) +- [Option B: Auto-Download from HuggingFace](#option-b-auto-download-from-huggingface) +- [Run Evaluation](#run-evaluation) +- [Understanding Results](#understanding-results) +- [All Domains Evaluation](#all-domains-evaluation) + +--- + +## Installation + +```bash +uv pip install -e examples/benchmarks/agent_leaderboard +``` + +This installs the `datasets` library for HuggingFace access. + +--- + +## Set Up Environment + +```bash +export NVIDIA_API_KEY= +``` + +--- + +## Option A: Download Dataset First + +Use the download script to fetch and transform the dataset: + +```bash +python examples/dynamo_integration/scripts/download_agent_leaderboard_v2.py \ + --output-dir data/agent_leaderboard \ + --domains banking +``` + +**Expected output:** +``` +INFO - Loading agent leaderboard v2 dataset from Hugging Face... +INFO - Loading domain: banking +INFO - Loaded 20 tools, 20 personas, 100 scenarios for banking +INFO - Saved 100 entries to data/agent_leaderboard/agent_leaderboard_v2_banking.json +INFO - Saved raw data to data/agent_leaderboard/raw/banking +``` + +Then set the data path: + +```bash +export AGENT_LEADERBOARD_DATA=data/agent_leaderboard/agent_leaderboard_v2_banking.json +``` + +--- + +## Option B: Auto-Download from HuggingFace + +If no local file is found, the dataset loader downloads directly from HuggingFace. Just point `file_path` to a non-existent path and the `domains` config will be used to download: + +```yaml +dataset: + _type: agent_leaderboard + file_path: ./data/auto_download.json # Will trigger HF download + domains: [banking] +``` + +--- + +## Run Evaluation + +### Banking domain (quick test with 10 scenarios) + +```bash +export AGENT_LEADERBOARD_LIMIT=10 +nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_banking.yml +``` + +**Expected output:** +``` +INFO - Starting evaluation run with config file: .../eval_banking.yml +INFO - Loaded 10 entries from data/agent_leaderboard/agent_leaderboard_v2_banking.json +INFO - Shared workflow built (entry_function=None) +Running workflow: 100%|██████████| 10/10 [03:20<00:00, 20.00s/it] +INFO - TSQ evaluation complete: avg_f1=0.650 across 10 scenarios + +=== EVALUATION SUMMARY === +| Evaluator | Avg Score | Output File | +|-----------|-------------|-----------------| +| tsq | 0.650 | tsq_output.json | +``` + +### Full banking evaluation + +```bash +unset AGENT_LEADERBOARD_LIMIT +nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_banking.yml +``` + +--- + +## Understanding Results + +```bash +python -c " +import json +with open('.tmp/nat/benchmarks/agent_leaderboard/banking/tsq_output.json') as f: + data = json.load(f) +print(f'Average TSQ F1: {data[\"average_score\"]:.3f}') +print(f'Total scenarios: {len(data[\"eval_output_items\"])}') + +for item in data['eval_output_items'][:3]: + r = item['reasoning'] + print(f' {item[\"id\"]}:') + print(f' F1={r[\"tool_selection_f1\"]:.2f} predicted={r[\"predicted_tools\"]}') + print(f' expected={r[\"expected_tools\"]}') +" +``` + +**Example output:** +``` +Average TSQ F1: 0.425 +Total scenarios: 100 + banking_scenario_000: + F1=0.67 predicted=['getaccountbalance', 'gettransactionhistory'] + expected=['getaccountbalance', 'transferfunds'] + banking_scenario_001: + F1=1.00 predicted=['getloaninformation'] + expected=['getloaninformation'] + banking_scenario_002: + F1=0.00 predicted=['scheduleappointment'] + expected=['getexchangerates'] +``` + +### TSQ Score interpretation + +| Score | Meaning | +|-------|---------| +| 1.0 | All expected tools predicted, no extra tools | +| 0.5-0.9 | Partial match — some tools correct, some missing or extra | +| 0.0 | No overlap between predicted and expected tools | + +--- + +## All Domains Evaluation + +Download all 5 domains: + +```bash +python examples/dynamo_integration/scripts/download_agent_leaderboard_v2.py \ + --output-dir data/agent_leaderboard \ + --domains banking healthcare insurance investment telecom +``` + +Run across all domains: + +```bash +export AGENT_LEADERBOARD_DATA=data/agent_leaderboard/agent_leaderboard_v2_all.json +nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_all_domains.yml +``` + +### Available domains + +| Domain | Description | Typical tool count | +|--------|-------------|-------------------| +| `banking` | Account management, transfers, loans | ~20 tools | +| `healthcare` | Appointments, prescriptions, records | ~15 tools | +| `insurance` | Policies, claims, coverage | ~15 tools | +| `investment` | Portfolio, stocks, trading | ~15 tools | +| `telecom` | Plans, billing, support | ~15 tools | diff --git a/examples/benchmarks/agent_leaderboard/configs b/examples/benchmarks/agent_leaderboard/configs new file mode 120000 index 0000000000..52253f2539 --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/configs @@ -0,0 +1 @@ +src/nat_benchmark_agent_leaderboard/configs \ No newline at end of file diff --git a/examples/benchmarks/agent_leaderboard/pyproject.toml b/examples/benchmarks/agent_leaderboard/pyproject.toml new file mode 100644 index 0000000000..7a6241a84c --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/pyproject.toml @@ -0,0 +1,31 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] + +[tool.setuptools_scm] +git_describe_command = "git describe --long --first-parent" +root = "../../.." + +[tool.setuptools.packages.find] +where = ["src"] + +[project] +name = "nat_benchmark_agent_leaderboard" +dynamic = ["version", "dependencies"] +requires-python = ">=3.11,<3.14" +description = "Galileo Agent Leaderboard v2 benchmark evaluation example for NeMo Agent Toolkit" +classifiers = ["Programming Language :: Python"] + +[tool.setuptools_dynamic_dependencies] +dependencies = [ + "nvidia-nat[eval,langchain,test] == {version}", + "nvidia-nat-benchmarks == {version}", + "datasets~=3.0", +] + +[tool.uv.sources] +nvidia-nat = { path = "../../..", editable = true } +nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } + +[project.entry-points.'nat.components'] +nat_benchmark_agent_leaderboard = "nat_benchmark_agent_leaderboard.register" diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py new file mode 100644 index 0000000000..fb0bad0357 --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +from . import register # noqa: F401 diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml new file mode 100644 index 0000000000..58688c6cb6 --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml @@ -0,0 +1,42 @@ +# Agent Leaderboard v2 — All domains evaluation +# Usage: nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_all_domains.yml + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 1024 + temperature: 0.0 + +workflow: + _type: agent_leaderboard_workflow + llm_name: nim_llm + max_steps: 10 + +eval: + general: + output_dir: .tmp/nat/benchmarks/agent_leaderboard/all_domains/ + workflow_alias: agent_leaderboard_all + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: agent_leaderboard + file_path: ${AGENT_LEADERBOARD_DATA:-./data/agent_leaderboard_v2_all.json} + domains: + - banking + - healthcare + - insurance + - investment + - telecom + limit: ${AGENT_LEADERBOARD_LIMIT:-} + structure: + question_key: question + answer_key: answer + + evaluators: + tsq: + _type: agent_leaderboard_tsq + tool_weight: 1.0 + parameter_weight: 0.0 diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml new file mode 100644 index 0000000000..2339b2f1ef --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml @@ -0,0 +1,38 @@ +# Agent Leaderboard v2 — Banking domain evaluation +# Usage: nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_banking.yml + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 1024 + temperature: 0.0 + +workflow: + _type: agent_leaderboard_workflow + llm_name: nim_llm + max_steps: 10 + +eval: + general: + output_dir: .tmp/nat/benchmarks/agent_leaderboard/banking/ + workflow_alias: agent_leaderboard_banking + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: agent_leaderboard + file_path: ${AGENT_LEADERBOARD_DATA:-./data/agent_leaderboard_v2_banking.json} + domains: + - banking + limit: ${AGENT_LEADERBOARD_LIMIT:-} + structure: + question_key: question + answer_key: answer + + evaluators: + tsq: + _type: agent_leaderboard_tsq + tool_weight: 1.0 + parameter_weight: 0.0 diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py new file mode 100644 index 0000000000..c278e4e89a --- /dev/null +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# Components are registered via nvidia-nat-benchmarks package entry points. +# This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/bfcl/README.md b/examples/benchmarks/bfcl/README.md new file mode 100644 index 0000000000..1f4261d460 --- /dev/null +++ b/examples/benchmarks/bfcl/README.md @@ -0,0 +1,178 @@ + + + +# BFCL Benchmark Evaluation + +**Complexity:** 🟡 Intermediate + +Evaluate NAT agent workflows against the [Berkeley Function Calling Leaderboard (BFCL)](https://gorilla.cs.berkeley.edu/leaderboard.html) v3 benchmark. BFCL tests single-turn function calling accuracy across simple, parallel, and multiple function call scenarios. + +This example supports **three evaluation modes** that demonstrate different NAT integration patterns: + +| Mode | Workflow Type | How it works | +|------|--------------|--------------| +| **AST Prompting** | `bfcl_ast_workflow` | Function schemas in system prompt; LLM outputs raw function call text | +| **Native FC** | `bfcl_fc_workflow` | `llm.bind_tools(schemas)` + `ainvoke()`; extracts structured `tool_calls` | +| **ReAct** | `bfcl_react_workflow` | Multi-step tool-calling loop with stub responses and intent capture | + +## Table of Contents + +- [Installation](#installation) +- [Set Up Environment](#set-up-environment) +- [Evaluation Mode 1: AST Prompting](#evaluation-mode-1-ast-prompting) +- [Evaluation Mode 2: Native Function Calling](#evaluation-mode-2-native-function-calling) +- [Evaluation Mode 3: ReAct Loop](#evaluation-mode-3-react-loop) +- [Understanding Results](#understanding-results) +- [Test Categories](#test-categories) + +--- + +## Installation + +```bash +uv pip install -e examples/benchmarks/bfcl +``` + +### Prerequisites + +The NVIDIA `bfcl` package must be installed (includes datasets and AST checker): + +```bash +pip install nvidia-bfcl +``` + +--- + +## Set Up Environment + +```bash +export NVIDIA_API_KEY= + +# Locate the BFCL dataset file +python -c " +from bfcl.constant import PROMPT_PATH +print(f'export BFCL_DATASET_FILE={PROMPT_PATH}/BFCL_v3_simple.json') +" +``` + +```bash +export BFCL_DATASET_FILE= +``` + +--- + +## Evaluation Mode 1: AST Prompting + +The LLM receives function schemas as JSON text in the system prompt and outputs raw function call text like `calculate_area(base=10, height=5)`. + +```bash +nat eval --config_file examples/benchmarks/bfcl/configs/eval_ast_simple.yml +``` + +**Expected output:** +``` +INFO - Starting evaluation run with config file: .../eval_ast_simple.yml +INFO - Loaded 3 possible answers from .../possible_answer/BFCL_v3_simple.json +INFO - Loaded 100 BFCL entries from BFCL_v3_simple.json (category: simple) +Running workflow: 100%|██████████| 100/100 [02:30<00:00, 1.50s/it] +INFO - BFCL evaluation complete: accuracy=0.850 (85/100) category=simple + +=== EVALUATION SUMMARY === +| Evaluator | Avg Score | Output File | +|-----------|-------------|------------------| +| bfcl | 0.850 | bfcl_output.json | +``` + +> The system prompt uses BFCL's standard format instruction which constrains the LLM to output +> `[func_name(param=value)]` format. Accuracy varies by model — `llama-3.3-70b-instruct` +> typically scores 80-95% on the simple split. + +--- + +## Evaluation Mode 2: Native Function Calling + +Uses `llm.bind_tools(schemas)` — the LLM makes structured tool calls via the native `tools=` API parameter. Tool call args are extracted from `AIMessage.tool_calls` and formatted for BFCL scoring. + +```bash +nat eval --config_file examples/benchmarks/bfcl/configs/eval_fc_simple.yml +``` + +This mode typically achieves higher accuracy than AST prompting because the LLM uses its native function calling capability rather than generating text. + +--- + +## Evaluation Mode 3: ReAct Loop + +Drives a multi-step reasoning loop: the LLM reasons about which tool to call, executes it (stub returns a canned response), observes the result, and decides whether to call more tools. Tool call intents are captured and deduplicated for scoring. + +```bash +nat eval --config_file examples/benchmarks/bfcl/configs/eval_react_simple.yml +``` + +This mode demonstrates NAT-native agent execution against BFCL — the agent can reason step-by-step before making tool calls. + +--- + +## Understanding Results + +Results are saved to `.tmp/nat/benchmarks/bfcl/_simple/`: + +```bash +python -c " +import json +with open('.tmp/nat/benchmarks/bfcl/ast_simple/bfcl_output.json') as f: + data = json.load(f) +print(f'Accuracy: {data[\"average_score\"]:.3f}') + +# Show first few results +for item in data['eval_output_items'][:5]: + status = 'PASS' if item['score'] == 1.0 else 'FAIL' + print(f' {item[\"id\"]}: {status}') + if item['score'] == 0.0: + r = item.get('reasoning', {}) + if 'error' in r: + print(f' Error: {r[\"error\"][:100]}') +" +``` + +**Example output:** +``` +Accuracy: 0.850 + simple_0: PASS + simple_1: PASS + simple_2: PASS + simple_3: FAIL + Error: ["Incorrect type for parameter 'x'. Expected type integer, got str."] + simple_4: PASS +``` + +### Score interpretation + +- **1.0**: Function name, parameter names, types, and values all match ground truth +- **0.0**: Any mismatch — wrong function, wrong params, wrong types, or unparseable output + +--- + +## Test Categories + +Change the `test_category` and `file_path` in the config to evaluate different BFCL splits: + +| Category | File | Description | +|----------|------|-------------| +| `simple` | `BFCL_v3_simple.json` | Single function call | +| `multiple` | `BFCL_v3_multiple.json` | Select one of multiple candidate functions | +| `parallel` | `BFCL_v3_parallel.json` | Multiple function calls in one response | +| `parallel_multiple` | `BFCL_v3_parallel_multiple.json` | Combined parallel + multiple | +| `java` | `BFCL_v3_java.json` | Java function call syntax | +| `javascript` | `BFCL_v3_javascript.json` | JavaScript function call syntax | +| `irrelevance` | `BFCL_v3_irrelevance.json` | Model should refuse (no valid tool) | + +For Java/JavaScript categories, set `language` in the evaluator config: + +```yaml +evaluators: + bfcl: + _type: bfcl_evaluator + test_category: java + language: Java +``` diff --git a/examples/benchmarks/bfcl/configs b/examples/benchmarks/bfcl/configs new file mode 120000 index 0000000000..bbf5fef498 --- /dev/null +++ b/examples/benchmarks/bfcl/configs @@ -0,0 +1 @@ +src/nat_benchmark_bfcl/configs \ No newline at end of file diff --git a/examples/benchmarks/bfcl/pyproject.toml b/examples/benchmarks/bfcl/pyproject.toml new file mode 100644 index 0000000000..dc36db96ff --- /dev/null +++ b/examples/benchmarks/bfcl/pyproject.toml @@ -0,0 +1,30 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] + +[tool.setuptools_scm] +git_describe_command = "git describe --long --first-parent" +root = "../../.." + +[tool.setuptools.packages.find] +where = ["src"] + +[project] +name = "nat_benchmark_bfcl" +dynamic = ["version", "dependencies"] +requires-python = ">=3.11,<3.14" +description = "BFCL (Berkeley Function Calling Leaderboard) benchmark evaluation example for NeMo Agent Toolkit" +classifiers = ["Programming Language :: Python"] + +[tool.setuptools_dynamic_dependencies] +dependencies = [ + "nvidia-nat[eval,langchain,test] == {version}", + "nvidia-nat-benchmarks == {version}", +] + +[tool.uv.sources] +nvidia-nat = { path = "../../..", editable = true } +nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } + +[project.entry-points.'nat.components'] +nat_benchmark_bfcl = "nat_benchmark_bfcl.register" diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py new file mode 100644 index 0000000000..fb0bad0357 --- /dev/null +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +from . import register # noqa: F401 diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml new file mode 100644 index 0000000000..45b30c2b35 --- /dev/null +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml @@ -0,0 +1,35 @@ +# BFCL v3 — AST Prompting on simple split +# Usage: nat eval --config_file examples/benchmarks/bfcl/configs/eval_ast_simple.yml + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 512 + temperature: 0.0 + +workflow: + _type: bfcl_ast_workflow + llm_name: nim_llm + +eval: + general: + output_dir: .tmp/nat/benchmarks/bfcl/ast_simple/ + workflow_alias: bfcl_ast_simple + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: bfcl + file_path: ${BFCL_DATASET_FILE} + test_category: simple + structure: + question_key: question + answer_key: answer + + evaluators: + bfcl: + _type: bfcl_evaluator + test_category: simple + language: Python diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml new file mode 100644 index 0000000000..687ef6b2b2 --- /dev/null +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml @@ -0,0 +1,35 @@ +# BFCL v3 — Native Function Calling on simple split +# Usage: nat eval --config_file examples/benchmarks/bfcl/configs/eval_fc_simple.yml + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 512 + temperature: 0.0 + +workflow: + _type: bfcl_fc_workflow + llm_name: nim_llm + +eval: + general: + output_dir: .tmp/nat/benchmarks/bfcl/fc_simple/ + workflow_alias: bfcl_fc_simple + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: bfcl + file_path: ${BFCL_DATASET_FILE} + test_category: simple + structure: + question_key: question + answer_key: answer + + evaluators: + bfcl: + _type: bfcl_evaluator + test_category: simple + language: Python diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml new file mode 100644 index 0000000000..1554ec2851 --- /dev/null +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml @@ -0,0 +1,36 @@ +# BFCL v3 — ReAct (tool-calling loop with intent capture) on simple split +# Usage: nat eval --config_file examples/benchmarks/bfcl/configs/eval_react_simple.yml + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 512 + temperature: 0.0 + +workflow: + _type: bfcl_react_workflow + llm_name: nim_llm + max_steps: 3 + +eval: + general: + output_dir: .tmp/nat/benchmarks/bfcl/react_simple/ + workflow_alias: bfcl_react_simple + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: bfcl + file_path: ${BFCL_DATASET_FILE} + test_category: simple + structure: + question_key: question + answer_key: answer + + evaluators: + bfcl: + _type: bfcl_evaluator + test_category: simple + language: Python diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py new file mode 100644 index 0000000000..c278e4e89a --- /dev/null +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# Components are registered via nvidia-nat-benchmarks package entry points. +# This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/byob/README.md b/examples/benchmarks/byob/README.md new file mode 100644 index 0000000000..3891bdf451 --- /dev/null +++ b/examples/benchmarks/byob/README.md @@ -0,0 +1,199 @@ + + + +# BYOB (Bring Your Own Benchmark) Evaluation + +**Complexity:** 🟢 Beginner + +Score NAT agent workflow outputs using [NeMo Evaluator's BYOB framework](https://docs.nvidia.com/nemo/evaluator/). BYOB lets you define custom benchmarks with any dataset and scorer — this example shows how to plug BYOB scorers into NAT's evaluation pipeline. + +## Key Features + +- **Any BYOB benchmark**: Use any benchmark defined with `@benchmark` + `@scorer` decorators +- **Built-in scorers**: `exact_match`, `contains`, `f1_token`, `bleu`, `rouge`, `regex_match` +- **Custom scorers**: Write your own scorer function with `ScorerInput` +- **No model_call_fn needed**: BYOB scorers run in-process — NAT handles the LLM calls +- **Dataset from benchmark**: Dataset path, prompt template, and target field come from the benchmark definition + +## Table of Contents + +- [Installation](#installation) +- [Step 1: Define a Benchmark](#step-1-define-a-benchmark) +- [Step 2: Configure the Evaluation](#step-2-configure-the-evaluation) +- [Step 3: Run the Evaluation](#step-3-run-the-evaluation) +- [Understanding Results](#understanding-results) +- [Built-in Scorers Reference](#built-in-scorers-reference) +- [Writing a Custom Scorer](#writing-a-custom-scorer) + +--- + +## Installation + +```bash +uv pip install -e examples/benchmarks/byob +``` + +### Prerequisites + +NeMo Evaluator must be installed for BYOB support: + +```bash +pip install nemo-evaluator +``` + +--- + +## Step 1: Define a Benchmark + +Create a Python file with your benchmark definition. Here's a minimal example using `exact_match`: + +```python +# my_benchmark.py +import json, os, tempfile +from nemo_evaluator.contrib.byob import ScorerInput, benchmark, scorer +from nemo_evaluator.contrib.byob.scorers import exact_match + +# Create a simple QA dataset +DATA = [ + {"id": "0", "question": "What is 2+2?", "target": "4"}, + {"id": "1", "question": "Capital of France?", "target": "Paris"}, + {"id": "2", "question": "Color of the sky?", "target": "blue"}, +] +DATASET_PATH = os.path.join(tempfile.gettempdir(), "my_qa_dataset.jsonl") +with open(DATASET_PATH, "w") as f: + for row in DATA: + f.write(json.dumps(row) + "\n") + +@benchmark( + name="my-qa-test", + dataset=DATASET_PATH, + prompt="{question}", + target_field="target", +) +@scorer +def my_scorer(sample: ScorerInput) -> dict: + return exact_match(sample) +``` + +--- + +## Step 2: Configure the Evaluation + +Set the benchmark module path: + +```bash +export BYOB_BENCHMARK_MODULE=/path/to/my_benchmark.py +export BYOB_BENCHMARK_NAME=my_qa_test # Normalized: hyphens become underscores +export NVIDIA_API_KEY= +``` + +--- + +## Step 3: Run the Evaluation + +```bash +nat eval --config_file examples/benchmarks/byob/configs/eval_exact_match.yml +``` + +**Expected output:** +``` +INFO - Starting evaluation run with config file: .../eval_exact_match.yml +INFO - Imported BYOB benchmark 'my-qa-test' (dataset: /tmp/my_qa_dataset.jsonl) +INFO - Loaded 3 BYOB samples from benchmark 'my-qa-test' +Running workflow: 100%|██████████| 3/3 [00:15<00:00, 5.00s/it] +INFO - BYOB evaluation complete: avg_correct=0.XXX (3 items) + +=== EVALUATION SUMMARY === +| Evaluator | Avg Score | Output File | +|-----------|-------------|------------------| +| byob | 0.XXX | byob_output.json | +``` + +--- + +## Understanding Results + +```bash +python -c " +import json +with open('.tmp/nat/benchmarks/byob/exact_match/byob_output.json') as f: + data = json.load(f) +print(f'Average score: {data[\"average_score\"]:.3f}') +for item in data['eval_output_items']: + r = item['reasoning'] + print(f' {item[\"id\"]}: score={item[\"score\"]} correct={r.get(\"correct\", \"N/A\")}') +" +``` + +**Example output:** +``` +Average score: 0.667 + 0: score=1.0 correct=True + 1: score=1.0 correct=True + 2: score=0.0 correct=False +``` + +--- + +## Built-in Scorers Reference + +| Scorer | Score field | Description | +|--------|-----------|-------------| +| `exact_match` | `correct` | Case-insensitive, whitespace-trimmed equality | +| `contains` | `correct` | Target is a substring of response | +| `f1_token` | `f1` | Token-level F1 (also returns `precision`, `recall`) | +| `regex_match` | `correct` | Target is a regex pattern matched against response | +| `bleu` | `bleu_1`..`bleu_4` | BLEU-1 through BLEU-4 with smoothing | +| `rouge` | `rouge_1`, `rouge_2`, `rouge_l` | ROUGE F1 scores | + +Set `score_field` in the evaluator config to match your scorer: + +```yaml +evaluators: + byob: + _type: byob_evaluator + benchmark_module: /path/to/benchmark.py + benchmark_name: my_benchmark + score_field: f1 # For f1_token scorer +``` + +--- + +## Writing a Custom Scorer + +```python +from nemo_evaluator.contrib.byob import ScorerInput, benchmark, scorer + +@benchmark( + name="my-custom-benchmark", + dataset="hf://squad", # HuggingFace dataset + prompt="Context: {context}\nQuestion: {question}\nAnswer:", + target_field="answers", +) +@scorer +def custom_scorer(sample: ScorerInput) -> dict: + """Score based on whether any valid answer appears in the response.""" + response = sample.response.lower() + target = sample.target + + # Handle SQuAD-style answers (list of valid answers) + if isinstance(target, dict) and "text" in target: + valid_answers = [a.lower() for a in target["text"]] + elif isinstance(target, list): + valid_answers = [str(a).lower() for a in target] + else: + valid_answers = [str(target).lower()] + + correct = any(answer in response for answer in valid_answers) + return {"correct": correct} +``` + +### ScorerInput fields + +| Field | Type | Description | +|-------|------|-------------| +| `response` | `str` | Model's generated response | +| `target` | `Any` | Ground-truth value from dataset | +| `metadata` | `dict` | Full dataset row | +| `model_call_fn` | `Optional[Callable]` | Always `None` in NAT (LLM calls handled by workflow) | +| `config` | `Dict[str, Any]` | Benchmark's `extra` config | diff --git a/examples/benchmarks/byob/configs b/examples/benchmarks/byob/configs new file mode 120000 index 0000000000..e13dedaf99 --- /dev/null +++ b/examples/benchmarks/byob/configs @@ -0,0 +1 @@ +src/nat_benchmark_byob/configs \ No newline at end of file diff --git a/examples/benchmarks/byob/pyproject.toml b/examples/benchmarks/byob/pyproject.toml new file mode 100644 index 0000000000..32042dac15 --- /dev/null +++ b/examples/benchmarks/byob/pyproject.toml @@ -0,0 +1,31 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] + +[tool.setuptools_scm] +git_describe_command = "git describe --long --first-parent" +root = "../../.." + +[tool.setuptools.packages.find] +where = ["src"] + +[project] +name = "nat_benchmark_byob" +dynamic = ["version", "dependencies"] +requires-python = ">=3.11,<3.14" +description = "BYOB (Bring Your Own Benchmark) evaluation example for NeMo Agent Toolkit" +classifiers = ["Programming Language :: Python"] + +[tool.setuptools_dynamic_dependencies] +dependencies = [ + "nvidia-nat[eval,langchain,test] == {version}", + "nvidia-nat-benchmarks == {version}", + "nemo-evaluator", +] + +[tool.uv.sources] +nvidia-nat = { path = "../../..", editable = true } +nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } + +[project.entry-points.'nat.components'] +nat_benchmark_byob = "nat_benchmark_byob.register" diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py b/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py new file mode 100644 index 0000000000..fb0bad0357 --- /dev/null +++ b/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +from . import register # noqa: F401 diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml b/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml new file mode 100644 index 0000000000..7952ff3d6b --- /dev/null +++ b/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml @@ -0,0 +1,41 @@ +# BYOB — Exact Match benchmark evaluation +# Usage: nat eval --config_file examples/benchmarks/byob/configs/eval_exact_match.yml +# +# This config uses any NAT workflow and scores its output against a +# BYOB benchmark definition using the exact_match scorer. + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 256 + temperature: 0.0 + +workflow: + _type: tool_calling_agent + llm_name: nim_llm + tool_names: [] + +eval: + general: + output_dir: .tmp/nat/benchmarks/byob/exact_match/ + workflow_alias: byob_exact_match + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: byob + file_path: placeholder + benchmark_module: ${BYOB_BENCHMARK_MODULE} + benchmark_name: ${BYOB_BENCHMARK_NAME} + structure: + question_key: question + answer_key: answer + + evaluators: + byob: + _type: byob_evaluator + benchmark_module: ${BYOB_BENCHMARK_MODULE} + benchmark_name: ${BYOB_BENCHMARK_NAME} + score_field: correct diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/register.py b/examples/benchmarks/byob/src/nat_benchmark_byob/register.py new file mode 100644 index 0000000000..c278e4e89a --- /dev/null +++ b/examples/benchmarks/byob/src/nat_benchmark_byob/register.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# Components are registered via nvidia-nat-benchmarks package entry points. +# This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/tooltalk/README.md b/examples/benchmarks/tooltalk/README.md new file mode 100644 index 0000000000..4685d25dc9 --- /dev/null +++ b/examples/benchmarks/tooltalk/README.md @@ -0,0 +1,191 @@ + + + +# ToolTalk Benchmark Evaluation + +**Complexity:** 🟡 Intermediate + +Evaluate NAT agent workflows against the [ToolTalk](https://github.com/microsoft/ToolTalk) multi-turn function calling benchmark. ToolTalk tests whether an agent can correctly select and execute API tools across multi-turn conversations with simulated database backends. + +## Key Features + +- **Multi-turn conversations**: Each scenario replays a full user-agent conversation with ground-truth tool calls +- **Simulated tool backends**: ToolTalk's `ToolExecutor` provides realistic database-backed tool responses +- **Native FC via `bind_tools()`**: Uses NAT's LangChain LLM with native function calling — no raw API calls +- **Built-in metrics**: Reports `recall`, `action_precision`, `bad_action_rate`, `success`, and `soft_success` +- **Easy + Full splits**: 29 easy conversations, 50 full conversations + +## Table of Contents + +- [Installation](#installation) +- [Set Up Environment](#set-up-environment) +- [Run Evaluation](#run-evaluation) +- [Understanding Results](#understanding-results) +- [Configuration Options](#configuration-options) + +--- + +## Installation + +From the root of the NeMo Agent Toolkit repository: + +```bash +uv pip install -e examples/benchmarks/tooltalk +``` + +This installs the `nvidia-nat-benchmarks` package which provides the ToolTalk dataset loader, workflow, and evaluator. + +### Prerequisites + +The `tooltalk` package must be installed. It ships with the dataset and simulated databases: + +```bash +pip install nvidia-tooltalk +``` + +--- + +## Set Up Environment + +### 1. Set your NVIDIA API key + +```bash +export NVIDIA_API_KEY= +``` + +Or add it to a `.env` file in your project root (NAT loads `.env` automatically). + +### 2. Locate ToolTalk data paths + +```bash +# Find the installed tooltalk data directories +python -c " +import tooltalk, os +base = os.path.dirname(tooltalk.__file__) +print(f'export TOOLTALK_DATABASE_DIR={os.path.join(base, \"data\", \"databases\")}') +print(f'export TOOLTALK_DATASET_DIR={os.path.join(base, \"data\", \"easy\")}') +" +``` + +**Expected output:** +``` +export TOOLTALK_DATABASE_DIR=/path/to/.venv/lib/python3.11/site-packages/tooltalk/data/databases +export TOOLTALK_DATASET_DIR=/path/to/.venv/lib/python3.11/site-packages/tooltalk/data/easy +``` + +Set both variables: + +```bash +export TOOLTALK_DATABASE_DIR= +export TOOLTALK_DATASET_DIR= +``` + +--- + +## Run Evaluation + +### Easy split (29 conversations) + +```bash +nat eval --config_file examples/benchmarks/tooltalk/configs/eval_easy.yml +``` + +**Expected output (during run):** +``` +INFO - Starting evaluation run with config file: examples/benchmarks/tooltalk/configs/eval_easy.yml +INFO - Loaded 29 ToolTalk conversations from /path/to/tooltalk/data/easy +INFO - Shared workflow built (entry_function=None) +Running workflow: 0%| | 0/29 [00:00=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] + +[tool.setuptools_scm] +git_describe_command = "git describe --long --first-parent" +root = "../../.." + +[tool.setuptools.packages.find] +where = ["src"] + +[project] +name = "nat_benchmark_tooltalk" +dynamic = ["version", "dependencies"] +requires-python = ">=3.11,<3.14" +description = "ToolTalk benchmark evaluation example for NeMo Agent Toolkit" +classifiers = ["Programming Language :: Python"] + +[tool.setuptools_dynamic_dependencies] +dependencies = [ + "nvidia-nat[eval,langchain,test] == {version}", + "nvidia-nat-benchmarks == {version}", +] + +[tool.uv.sources] +nvidia-nat = { path = "../../..", editable = true } +nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } + +[project.entry-points.'nat.components'] +nat_benchmark_tooltalk = "nat_benchmark_tooltalk.register" diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py new file mode 100644 index 0000000000..fb0bad0357 --- /dev/null +++ b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +from . import register # noqa: F401 diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml new file mode 100644 index 0000000000..1413e719da --- /dev/null +++ b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml @@ -0,0 +1,37 @@ +# ToolTalk Easy Split — Multi-turn function calling evaluation +# Usage: nat eval --config_file examples/benchmarks/tooltalk/configs/eval_easy.yml + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 1024 + temperature: 0.0 + +workflow: + _type: tooltalk_workflow + llm_name: nim_llm + database_dir: ${TOOLTALK_DATABASE_DIR} + api_mode: all + max_tool_calls_per_turn: 5 + +eval: + general: + output_dir: .tmp/nat/benchmarks/tooltalk/easy/ + workflow_alias: tooltalk_easy + per_input_user_id: true + max_concurrency: 3 + dataset: + _type: tooltalk + file_path: ${TOOLTALK_DATASET_DIR} + database_dir: ${TOOLTALK_DATABASE_DIR} + structure: + question_key: question + answer_key: answer + + evaluators: + tooltalk: + _type: tooltalk_evaluator + database_dir: ${TOOLTALK_DATABASE_DIR} diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py new file mode 100644 index 0000000000..c278e4e89a --- /dev/null +++ b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# Components are registered via nvidia-nat-benchmarks package entry points. +# This register.py exists for the example package structure convention. diff --git a/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml b/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml new file mode 100644 index 0000000000..5bf488a6e5 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml @@ -0,0 +1,46 @@ +# Agent Leaderboard v2 evaluation config for NAT +# Usage: nat eval --config_file packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml +# +# Prerequisite: Download dataset first: +# python examples/dynamo_integration/scripts/download_agent_leaderboard_v2.py \ +# --output-dir data/agent_leaderboard --domains banking healthcare insurance investment telecom +# +# Required env vars: +# NVIDIA_API_KEY — API key for NVIDIA NIM endpoint +# AGENT_LEADERBOARD_DATA — path to downloaded JSON file (or will download from HuggingFace) + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 1024 + temperature: 0.0 + +workflow: + _type: agent_leaderboard_workflow + llm_name: nim_llm + max_steps: 10 + +eval: + general: + output_dir: .tmp/nat/benchmarks/agent_leaderboard/output/ + workflow_alias: agent_leaderboard_llama33_70b + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: agent_leaderboard + file_path: ${AGENT_LEADERBOARD_DATA:-./data/agent_leaderboard/agent_leaderboard_v2_banking.json} + domains: + - banking + structure: + question_key: question + answer_key: answer + disable: true + + evaluators: + tsq: + _type: agent_leaderboard_tsq + tool_weight: 1.0 + parameter_weight: 0.0 diff --git a/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml b/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml new file mode 100644 index 0000000000..fbd93c0471 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml @@ -0,0 +1,39 @@ +# BFCL v3 AST prompting evaluation config for NAT +# Usage: nat eval --config_file packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml +# +# Required env vars: +# NVIDIA_API_KEY — API key for NVIDIA NIM endpoint +# BFCL_DATASET_FILE — path to BFCL v3 test JSONL (e.g. .../bfcl/data/BFCL_v3_simple.json) + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 512 + temperature: 0.0 + +workflow: + _type: bfcl_ast_workflow + llm_name: nim_llm + +eval: + general: + output_dir: .tmp/nat/benchmarks/bfcl_ast/output/ + workflow_alias: bfcl_ast_llama33_70b + per_input_user_id: false + max_concurrency: 5 + dataset: + _type: bfcl + file_path: ${BFCL_DATASET_FILE} + test_category: simple + structure: + question_key: question + answer_key: answer + + evaluators: + bfcl: + _type: bfcl_evaluator + test_category: simple + language: Python diff --git a/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml b/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml new file mode 100644 index 0000000000..e3644759c6 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml @@ -0,0 +1,42 @@ +# ToolTalk benchmark evaluation config for NAT +# Usage: nat eval --config-file packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml +# +# Required env vars (can be set in .env): +# NVIDIA_API_KEY — API key for NVIDIA NIM endpoint +# TOOLTALK_DATABASE_DIR — path to ToolTalk database dir (e.g. .venv/.../tooltalk/data/databases) +# TOOLTALK_DATASET_DIR — path to ToolTalk dataset dir (e.g. .venv/.../tooltalk/data/easy) + +llms: + nim_llm: + _type: nim + model_name: meta/llama-3.3-70b-instruct + base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} + api_key: ${NVIDIA_API_KEY} + max_tokens: 1024 + temperature: 0.0 + +workflow: + _type: tooltalk_workflow + llm_name: nim_llm + database_dir: ${TOOLTALK_DATABASE_DIR} + api_mode: all + disable_documentation: false + +eval: + general: + output_dir: .tmp/nat/benchmarks/tooltalk/output/ + workflow_alias: tooltalk_llama33_70b + per_input_user_id: true + max_concurrency: 3 + dataset: + _type: tooltalk + file_path: ${TOOLTALK_DATASET_DIR} + database_dir: ${TOOLTALK_DATABASE_DIR} + structure: + question_key: question + answer_key: answer + + evaluators: + tooltalk: + _type: tooltalk_evaluator + database_dir: ${TOOLTALK_DATABASE_DIR} diff --git a/packages/nvidia_nat_benchmarks/pyproject.toml b/packages/nvidia_nat_benchmarks/pyproject.toml new file mode 100644 index 0000000000..666239ef50 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/pyproject.toml @@ -0,0 +1,82 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. +# All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] + + +[tool.setuptools.packages.find] +where = ["src"] +include = ["nat.*"] + + +[tool.setuptools_scm] +git_describe_command = "git describe --long --first-parent" +root = "../.." + + +[project] +name = "nvidia-nat-benchmarks" +dynamic = ["version", "dependencies", "optional-dependencies"] +requires-python = ">=3.11,<3.14" +description = "Agent benchmarks for NVIDIA NeMo Agent Toolkit workflows" +keywords = ["ai", "agents", "evaluation", "benchmarks", "function-calling"] +license = { text = "Apache-2.0" } +authors = [{ name = "NVIDIA Corporation" }] +maintainers = [{ name = "NVIDIA Corporation" }] +classifiers = [ + "Programming Language :: Python", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] + +[project.urls] +documentation = "https://docs.nvidia.com/nemo/agent-toolkit/latest/" +source = "https://github.com/NVIDIA/NeMo-Agent-Toolkit" + +[tool.setuptools_dynamic_dependencies] +dependencies = [ + # Keep sorted!!! + "nvidia-nat-core == {version}", + "nvidia-nat-eval == {version}", + "nvidia-nat-langchain == {version}", +] + +[tool.setuptools_dynamic_dependencies.optional-dependencies] +tooltalk = [ + "tooltalk", +] +test = [ + "nvidia-nat-core[async_endpoints] == {version}", + "nvidia-nat-test == {version}", + "tooltalk", +] + +[tool.uv] +build-constraint-dependencies = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] +managed = true +config-settings = { editable_mode = "compat" } + +[tool.uv.sources] +nvidia-nat-core = { path = "../nvidia_nat_core", editable = true } +nvidia-nat-eval = { path = "../nvidia_nat_eval", editable = true } +nvidia-nat-langchain = { path = "../nvidia_nat_langchain", editable = true } +nvidia-nat-test = { path = "../nvidia_nat_test", editable = true } + +[project.entry-points.'nat.components'] +nat_benchmarks = "nat.plugins.benchmarks.register" diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py new file mode 100644 index 0000000000..c09cac23e1 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py @@ -0,0 +1,66 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Configuration types for Galileo Agent Leaderboard v2 benchmark.""" + +from collections.abc import Callable + +from pydantic import Field + +from nat.data_models.agent import AgentBaseConfig +from nat.data_models.dataset_handler import EvalDatasetBaseConfig +from nat.data_models.evaluator import EvaluatorBaseConfig + +AVAILABLE_DOMAINS = ["banking", "healthcare", "insurance", "investment", "telecom"] + + +class AgentLeaderboardDatasetConfig(EvalDatasetBaseConfig, name="agent_leaderboard"): + """Dataset config for Galileo Agent Leaderboard v2. + + Downloads scenarios from HuggingFace galileo-ai/agent-leaderboard-v2. + Each scenario has a user message, user_goals, and available tools. + """ + + domains: list[str] = Field( + default=["banking"], + description=f"Domains to include: {AVAILABLE_DOMAINS}", + ) + limit: int | None = Field( + default=None, + description="Max scenarios to load (for testing)", + ) + + def parser(self) -> tuple[Callable, dict]: + from .dataset import load_agent_leaderboard_dataset + return load_agent_leaderboard_dataset, {"domains": self.domains, "limit": self.limit} + + +class AgentLeaderboardWorkflowConfig(AgentBaseConfig, name="agent_leaderboard_workflow"): + """Workflow config for Agent Leaderboard evaluation. + + Uses tool_calling_agent with stub tools from the dataset. + Tool calls are captured via ToolIntentBuffer for TSQ scoring. + """ + + description: str = Field(default="Agent Leaderboard Workflow") + max_steps: int = Field( + default=10, + description="Maximum tool-calling steps per scenario", + ) + system_prompt: str | None = Field( + default=( + "You are a tool-calling agent. Select the correct tools to handle the user's request.\n" + "Focus on selecting the RIGHT TOOL for each step. Use placeholder values for parameters.\n" + "Tool responses are simulated — focus on tool choice, not data quality." + ), + description="System prompt for the agent", + ) + + +class TSQEvaluatorConfig(EvaluatorBaseConfig, name="agent_leaderboard_tsq"): + """Tool Selection Quality evaluator for Agent Leaderboard. + + Computes F1 score between predicted and expected tool calls. + """ + + tool_weight: float = Field(default=1.0, description="Weight for tool selection accuracy") + parameter_weight: float = Field(default=0.0, description="Weight for parameter accuracy") diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py new file mode 100644 index 0000000000..e65ddf109e --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py @@ -0,0 +1,165 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Agent Leaderboard v2 dataset loader. + +Downloads from HuggingFace galileo-ai/agent-leaderboard-v2 and transforms +scenarios into a DataFrame for NAT's eval runner. +""" + +import json +import logging +from pathlib import Path + +import pandas as pd + +from nat.builder.builder import EvalBuilder +from nat.builder.dataset_loader import DatasetLoaderInfo +from nat.cli.register_workflow import register_dataset_loader + +from .config import AgentLeaderboardDatasetConfig + +logger = logging.getLogger(__name__) + + +def _convert_tool_json_strings(tool_record: dict) -> dict: + """Convert tool JSON string fields to proper dicts.""" + tool = dict(tool_record) + for field in ("properties", "response_schema"): + if field in tool and isinstance(tool[field], str): + tool[field] = json.loads(tool[field]) + return tool + + +def _derive_expected_tool_calls(user_goals: list[str], tools: list[dict]) -> list[dict]: + """Heuristic: match goal keywords to tool names/descriptions.""" + keyword_mappings = { + "balance": ["balance", "check", "account"], + "transfer": ["transfer", "send", "move", "pay"], + "transaction": ["transaction", "history", "statement"], + "payment": ["payment", "pay", "bill"], + "card": ["card", "credit", "debit"], + "loan": ["loan", "mortgage", "credit"], + "dispute": ["dispute", "challenge", "report"], + "limit": ["limit", "increase", "decrease"], + "block": ["block", "freeze", "lock"], + "appointment": ["appointment", "schedule", "book"], + "contact": ["contact", "phone", "email", "address", "update"], + "wire": ["wire", "international", "swift"], + "exchange": ["exchange", "rate", "currency", "convert"], + "investment": ["investment", "portfolio", "stock"], + "insurance": ["insurance", "policy", "claim", "coverage"], + "health": ["health", "medical", "prescription", "doctor"], + } + + expected = [] + seen = set() + for goal in user_goals: + goal_lower = goal.lower() + for tool in tools: + tool_name = tool.get("title", "") + tool_desc = tool.get("description", "").lower() + tool_name_lower = tool_name.lower() + + for keyword, patterns in keyword_mappings.items(): + if keyword in goal_lower and any( + p in tool_name_lower or p in tool_desc for p in patterns + ): + if tool_name not in seen: + seen.add(tool_name) + expected.append({"tool": tool_name, "parameters": {}}) + break + + return expected + + +def load_agent_leaderboard_dataset( + file_path: str | Path, + domains: list[str] | None = None, + limit: int | None = None, +) -> pd.DataFrame: + """Load the Galileo Agent Leaderboard v2 dataset. + + If file_path points to an existing JSON file, loads from disk. + Otherwise, downloads from HuggingFace. + """ + file_path = Path(file_path) + + # If a pre-downloaded file exists, use it + if file_path.is_file(): + with open(file_path, encoding="utf-8") as f: + entries = json.load(f) + logger.info("Loaded %d entries from %s", len(entries), file_path) + else: + # Download from HuggingFace + entries = _download_from_huggingface(domains or ["banking"]) + logger.info("Downloaded %d entries from HuggingFace", len(entries)) + + if limit: + entries = entries[:limit] + + rows = [] + for entry in entries: + rows.append({ + "id": entry.get("id", ""), + "question": json.dumps(entry), + "answer": json.dumps(entry.get("expected_tool_calls", [])), + }) + + return pd.DataFrame(rows) + + +def _download_from_huggingface(domains: list[str]) -> list[dict]: + """Download and transform from galileo-ai/agent-leaderboard-v2.""" + from datasets import load_dataset + + all_entries = [] + for domain in domains: + try: + tools_ds = load_dataset("galileo-ai/agent-leaderboard-v2", "tools", split=domain) + personas_ds = load_dataset("galileo-ai/agent-leaderboard-v2", "personas", split=domain) + scenarios_ds = load_dataset("galileo-ai/agent-leaderboard-v2", "adaptive_tool_use", split=domain) + + tools = [_convert_tool_json_strings(dict(t)) for t in tools_ds] + personas = [dict(p) for p in personas_ds] + + for idx, scenario in enumerate(scenarios_ds): + scenario = dict(scenario) + user_goals = scenario.get("user_goals", []) + expected_tool_calls = _derive_expected_tool_calls(user_goals, tools) + + persona_idx = scenario.get("persona_index", idx) + persona = personas[persona_idx] if persona_idx < len(personas) else {} + + all_entries.append({ + "id": f"{domain}_scenario_{idx:03d}", + "question": scenario.get("first_message", ""), + "ground_truth": "User goals:\n" + "\n".join(f"- {g}" for g in user_goals), + "user_goals": user_goals, + "available_tools": tools, + "expected_tool_calls": expected_tool_calls, + "metadata": { + "domain": domain, + "persona_name": persona.get("name", ""), + "num_goals": len(user_goals), + }, + }) + + logger.info("Loaded %d scenarios from domain '%s'", len(scenarios_ds), domain) + + except Exception: + logger.exception("Failed to load domain '%s'", domain) + + return all_entries + + +@register_dataset_loader(config_type=AgentLeaderboardDatasetConfig) +async def register_agent_leaderboard_dataset_loader( + config: AgentLeaderboardDatasetConfig, builder: EvalBuilder +): + yield DatasetLoaderInfo( + config=config, + load_fn=lambda fp, **kw: load_agent_leaderboard_dataset( + fp, domains=config.domains, limit=config.limit, **kw + ), + description="Galileo Agent Leaderboard v2 dataset loader", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py new file mode 100644 index 0000000000..3383b12b7d --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py @@ -0,0 +1,139 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tool Selection Quality (TSQ) evaluator for Agent Leaderboard. + +Computes F1 score between predicted tool calls (from workflow output) +and expected tool calls (from dataset ground truth). +""" + +import json +import logging + +from nat.builder.builder import EvalBuilder +from nat.builder.evaluator import EvaluatorInfo +from nat.cli.register_workflow import register_evaluator +from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem + +from .config import TSQEvaluatorConfig + +logger = logging.getLogger(__name__) + + +def _normalize_tool_name(name: str) -> str: + """Normalize tool name for comparison (lowercase, strip separators).""" + if not name: + return "" + # Strip module prefix (e.g. "banking_tools__get_balance" -> "get_balance") + if "__" in name: + name = name.split("__", 1)[1] + return name.lower().strip().replace("_", "").replace("-", "") + + +def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: float) -> EvalOutputItem: + """Evaluate tool selection quality for a single scenario.""" + if item.output_obj is None: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": "No workflow output"}, + ) + + # Parse predicted tool calls from workflow output + try: + predicted = json.loads(item.output_obj) if isinstance(item.output_obj, str) else item.output_obj + if not isinstance(predicted, list): + predicted = [] + except (json.JSONDecodeError, TypeError): + predicted = [] + + # Parse expected tool calls from ground truth + # The full_dataset_entry from DatasetHandler is a DataFrame row with 'question' as serialized JSON. + # We need to parse that JSON to get the actual entry with expected_tool_calls. + full_entry = item.full_dataset_entry + if isinstance(full_entry, str): + try: + full_entry = json.loads(full_entry) + except (json.JSONDecodeError, TypeError): + full_entry = {} + if not isinstance(full_entry, dict): + full_entry = {} + + # Check if expected_tool_calls is directly in full_entry + expected = full_entry.get("expected_tool_calls", []) + + # If not found, try parsing the 'question' field (which contains the serialized entry) + if not expected and "question" in full_entry: + try: + question_data = json.loads(full_entry["question"]) if isinstance(full_entry["question"], str) else full_entry["question"] + if isinstance(question_data, dict): + expected = question_data.get("expected_tool_calls", []) + except (json.JSONDecodeError, TypeError): + pass + + # Also try input_obj as a last resort + if not expected and item.input_obj: + try: + input_data = json.loads(item.input_obj) if isinstance(item.input_obj, str) else item.input_obj + if isinstance(input_data, dict): + expected = input_data.get("expected_tool_calls", []) + except (json.JSONDecodeError, TypeError): + pass + + # Calculate tool selection F1 + predicted_tools = {_normalize_tool_name(tc.get("tool", "")) for tc in predicted} - {""} + expected_tools = {_normalize_tool_name(tc.get("tool", "")) for tc in expected} - {""} + + if not expected_tools: + tool_f1 = 1.0 if not predicted_tools else 0.0 + else: + correct = len(predicted_tools & expected_tools) + precision = correct / len(predicted_tools) if predicted_tools else 0.0 + recall = correct / len(expected_tools) + tool_f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0.0 + + # Parameter accuracy (simplified: just check if expected params are present) + param_accuracy = 1.0 # Placeholder — full param matching is optional + + score = tool_weight * tool_f1 + parameter_weight * param_accuracy + + return EvalOutputItem( + id=item.id, + score=score, + reasoning={ + "tool_selection_f1": tool_f1, + "parameter_accuracy": param_accuracy, + "predicted_tools": sorted(predicted_tools), + "expected_tools": sorted(expected_tools), + "num_predicted": len(predicted), + "num_expected": len(expected), + }, + ) + + +@register_evaluator(config_type=TSQEvaluatorConfig) +async def agent_leaderboard_tsq_evaluator(config: TSQEvaluatorConfig, builder: EvalBuilder): + + async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: + eval_output_items = [] + + for item in eval_input.eval_input_items: + try: + output_item = _evaluate_single(item, config.tool_weight, config.parameter_weight) + except Exception as e: + logger.exception("Error evaluating TSQ for item %s: %s", item.id, e) + output_item = EvalOutputItem( + id=item.id, score=0.0, reasoning={"error": str(e)}, + ) + eval_output_items.append(output_item) + + scores = [i.score for i in eval_output_items if isinstance(i.score, (int, float))] + average_score = sum(scores) / len(scores) if scores else 0.0 + + logger.info("TSQ evaluation complete: avg_f1=%.3f across %d scenarios", average_score, len(scores)) + + return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) + + yield EvaluatorInfo( + config=config, + evaluate_fn=evaluate_fn, + description="Tool Selection Quality (TSQ) evaluator for Agent Leaderboard", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py new file mode 100644 index 0000000000..36671d7007 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py @@ -0,0 +1,121 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Agent Leaderboard workflow. + +Drives a tool-calling loop using tool stubs from the dataset. +Each scenario's available_tools are converted to OpenAI tool schemas, +bound to the LLM, and tool call intents are captured for TSQ scoring. +""" + +import hashlib +import json +import logging + +from nat.builder.builder import Builder +from nat.builder.framework_enum import LLMFrameworkEnum +from nat.builder.function_info import FunctionInfo +from nat.cli.register_workflow import register_function + +from ..bfcl.tool_intent_stubs import ( + ToolIntentBuffer, + clear_global_intents, + get_global_intents, + set_current_scenario_id, +) +from .config import AgentLeaderboardWorkflowConfig + +logger = logging.getLogger(__name__) + + +def _tool_schema_to_openai(tool: dict) -> dict: + """Convert an Agent Leaderboard tool schema to OpenAI function calling format.""" + properties = {} + for name, prop in tool.get("properties", {}).items(): + converted = dict(prop) if isinstance(prop, dict) else {"type": "string", "description": str(prop)} + properties[name] = converted + + return { + "type": "function", + "function": { + "name": tool.get("title", "unknown"), + "description": tool.get("description", ""), + "parameters": { + "type": "object", + "properties": properties, + "required": tool.get("required", []), + }, + }, + } + + +@register_function( + config_type=AgentLeaderboardWorkflowConfig, + framework_wrappers=[LLMFrameworkEnum.LANGCHAIN], +) +async def agent_leaderboard_workflow(config: AgentLeaderboardWorkflowConfig, builder: Builder): + from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage + + llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) + + async def _run(input_json: str) -> str: + """Run a single scenario: bind stub tools, call LLM, capture intents.""" + entry = json.loads(input_json) + tools = entry.get("available_tools", []) + question = entry.get("question", "") + + if not tools: + return json.dumps([]) + + # Scenario isolation + scenario_id = f"al_{hashlib.md5(input_json[:200].encode()).hexdigest()[:12]}" + token = set_current_scenario_id(scenario_id) + clear_global_intents(scenario_id) + intent_buffer = ToolIntentBuffer() + + try: + # Convert all domain tools to OpenAI format + openai_tools = [_tool_schema_to_openai(t) for t in tools] + bound_llm = llm.bind_tools(openai_tools) + + # Build messages + messages = [] + if config.system_prompt: + messages.append(SystemMessage(content=config.system_prompt)) + messages.append(HumanMessage(content=question)) + + # Tool-calling loop + for step in range(config.max_steps): + response = await bound_llm.ainvoke(messages) + + if not response.tool_calls: + break + + for tc in response.tool_calls: + name = tc["name"] + args = dict(tc["args"]) if tc["args"] else {} + + intent_buffer.record(name, args) + + # Canned response + canned = f"Successfully executed {name}. Operation completed." + messages.append(AIMessage( + content="", + tool_calls=[{ + "name": name, + "args": args, + "id": tc.get("id", f"call_{step}_{name}"), + }], + )) + messages.append(ToolMessage( + content=canned, + tool_call_id=tc.get("id", f"call_{step}_{name}"), + )) + + # Return captured intents as JSON + intents = intent_buffer.get_intents() + return json.dumps(intents) + + finally: + clear_global_intents(scenario_id) + + yield FunctionInfo.from_fn(_run, description=config.description) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py new file mode 100644 index 0000000000..0576180b24 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py @@ -0,0 +1,78 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Configuration types for the BFCL benchmark.""" + +from collections.abc import Callable +from typing import Literal + +from pydantic import Field + +from nat.data_models.agent import AgentBaseConfig +from nat.data_models.dataset_handler import EvalDatasetBaseConfig +from nat.data_models.evaluator import EvaluatorBaseConfig + + +# Valid BFCL v3 single-turn AST test categories +BFCL_AST_CATEGORIES = [ + "simple", "multiple", "parallel", "parallel_multiple", + "java", "javascript", + "live_simple", "live_multiple", "live_parallel", "live_parallel_multiple", + "irrelevance", "live_irrelevance", "live_relevance", +] + + +class BFCLDatasetConfig(EvalDatasetBaseConfig, name="bfcl"): + """Dataset config for BFCL benchmark. + + file_path should point to a BFCL v3 JSONL test file (e.g. BFCL_v3_simple.json). + """ + + test_category: str = Field( + default="simple", + description="BFCL test category: simple, multiple, parallel, parallel_multiple, " + "java, javascript, irrelevance, live_simple, etc.", + ) + possible_answer_file: str | None = Field( + default=None, + description="Path to the BFCL possible_answer file. If None, auto-resolves from bfcl package.", + ) + + def parser(self) -> tuple[Callable, dict]: + from .dataset import load_bfcl_dataset + return load_bfcl_dataset, {"test_category": self.test_category} + + +class BFCLASTWorkflowConfig(AgentBaseConfig, name="bfcl_ast_workflow"): + """Workflow config for BFCL AST (prompting) evaluation. + + The LLM receives function schemas as text in the system prompt and outputs + raw function call text (e.g. `func_name(param=value)`). No tools= parameter. + """ + + description: str = Field(default="BFCL AST Prompting Workflow") + + +class BFCLFCWorkflowConfig(AgentBaseConfig, name="bfcl_fc_workflow"): + """Workflow config for BFCL Native FC evaluation. + + Uses llm.bind_tools(schemas) + ainvoke() — Native Function Calling. + Extracts tool_calls from AIMessage and formats as BFCL expected output. + """ + + description: str = Field(default="BFCL Native FC Workflow") + + +class BFCLEvaluatorConfig(EvaluatorBaseConfig, name="bfcl_evaluator"): + """Evaluator config for BFCL AST/FC benchmark. + + Calls BFCL's ast_checker directly in-process for scoring. + """ + + test_category: str = Field( + default="simple", + description="BFCL test category (must match the dataset config).", + ) + language: str = Field( + default="Python", + description="Programming language for AST parsing: Python, Java, or JavaScript.", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py new file mode 100644 index 0000000000..9e01704ec2 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py @@ -0,0 +1,96 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BFCL dataset loader. + +Loads BFCL v3 JSONL test files into a DataFrame compatible with NAT's eval runner. +Each row contains the user question, function schemas, and ground truth answer. +""" + +import json +import logging +from pathlib import Path + +import pandas as pd + +from nat.builder.builder import EvalBuilder +from nat.builder.dataset_loader import DatasetLoaderInfo +from nat.cli.register_workflow import register_dataset_loader + +from .config import BFCLDatasetConfig + +logger = logging.getLogger(__name__) + + +def _resolve_possible_answer_path(test_file: Path, test_category: str) -> Path | None: + """Auto-resolve the possible_answer file from the bfcl package.""" + # Try sibling directory + possible_dir = test_file.parent / "possible_answer" + candidate = possible_dir / test_file.name + if candidate.is_file(): + return candidate + + # Try bfcl package data + try: + from bfcl.constant import POSSIBLE_ANSWER_PATH + candidate = Path(POSSIBLE_ANSWER_PATH) / test_file.name + if candidate.is_file(): + return candidate + except ImportError: + pass + + return None + + +def load_bfcl_dataset(file_path: str | Path, test_category: str = "simple") -> pd.DataFrame: + """Load a BFCL v3 JSONL file into a DataFrame. + + Each row gets: + - id: the BFCL test ID (e.g. "simple_0") + - question: serialized JSON with the full test entry (question + function schemas) + - answer: serialized JSON with the ground truth possible answer + """ + file_path = Path(file_path) + if not file_path.is_file(): + raise ValueError(f"BFCL dataset file not found: {file_path}") + + # Load test prompts + with open(file_path, encoding="utf-8") as f: + entries = [json.loads(line) for line in f if line.strip()] + + # Load possible answers + answer_path = _resolve_possible_answer_path(file_path, test_category) + answers_by_id = {} + if answer_path and answer_path.is_file(): + with open(answer_path, encoding="utf-8") as f: + for line in f: + if line.strip(): + ans = json.loads(line) + answers_by_id[ans["id"]] = ans + logger.info("Loaded %d possible answers from %s", len(answers_by_id), answer_path) + else: + logger.warning("No possible_answer file found for %s — evaluator will have no ground truth", file_path.name) + + rows = [] + for entry in entries: + entry_id = entry["id"] + answer = answers_by_id.get(entry_id, {"id": entry_id, "ground_truth": []}) + rows.append({ + "id": entry_id, + "question": json.dumps(entry), + "answer": json.dumps(answer), + }) + + if not rows: + raise ValueError(f"No entries found in BFCL dataset: {file_path}") + + logger.info("Loaded %d BFCL entries from %s (category: %s)", len(rows), file_path.name, test_category) + return pd.DataFrame(rows) + + +@register_dataset_loader(config_type=BFCLDatasetConfig) +async def register_bfcl_dataset_loader(config: BFCLDatasetConfig, builder: EvalBuilder): + yield DatasetLoaderInfo( + config=config, + load_fn=lambda fp, **kw: load_bfcl_dataset(fp, test_category=config.test_category, **kw), + description="BFCL v3 benchmark dataset loader", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py new file mode 100644 index 0000000000..2d3e28776a --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py @@ -0,0 +1,240 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BFCL benchmark evaluator. + +Calls BFCL's ast_checker directly in-process to score model outputs. +Supports both AST prompting and FC workflow outputs. +""" + +import json +import logging + +from nat.builder.builder import EvalBuilder +from nat.builder.evaluator import EvaluatorInfo +from nat.cli.register_workflow import register_evaluator +from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem + +from .config import BFCLEvaluatorConfig + +logger = logging.getLogger(__name__) + + +def _extract_function_call(raw_output: str) -> str: + """Extract function call text from model output, stripping markdown and prose.""" + import re + + # Try to extract from markdown code blocks first (python, json, tool_code, or untagged) + code_blocks = re.findall(r'```(?:python|tool_code|json)?\s*\n?(.*?)\n?```', raw_output, re.DOTALL) + if code_blocks: + block = code_blocks[-1].strip() + # If it's JSON with "name"/"parameters", convert to function call + converted = _try_convert_json_to_call(block) + if converted: + return converted + # If it's Python code with imports, extract just the function call lines + if block.startswith("import ") or block.startswith("from "): + calls = _extract_calls_from_code(block) + if calls: + return calls + return block + + # Try JSON-formatted tool call (without code block) + converted = _try_convert_json_to_call(raw_output.strip()) + if converted: + return converted + + # Try to find lines that look like function calls (name(...)) + lines = raw_output.strip().split('\n') + func_call_lines = [] + for line in lines: + stripped = line.strip() + # Remove common prefixes + for prefix in ['tools.', '> ', '- ']: + if stripped.startswith(prefix): + stripped = stripped[len(prefix):] + if re.match(r'^[a-zA-Z_]\w*(?:\.\w+)*\s*\(', stripped): + func_call_lines.append(stripped) + + if func_call_lines: + # Strip 'tools.' prefix from extracted calls + func_call_lines = [re.sub(r'^tools\.', '', c) for c in func_call_lines] + if len(func_call_lines) == 1: + return func_call_lines[0] + return '[' + ', '.join(func_call_lines) + ']' + + # If the whole output looks like Python code with imports, extract calls + if raw_output.strip().startswith("import ") or raw_output.strip().startswith("from "): + calls = _extract_calls_from_code(raw_output.strip()) + if calls: + return calls + + # If the whole output looks like Python code with imports, extract calls + if raw_output.strip().startswith("import ") or raw_output.strip().startswith("from "): + calls = _extract_calls_from_code(raw_output.strip()) + if calls: + return calls + + # Fallback: return as-is and let the AST parser try + return raw_output + + +def _try_convert_json_to_call(text: str) -> str | None: + """Try to parse JSON tool-call format and convert to Python function call.""" + import json as _json + try: + obj = _json.loads(text) + if isinstance(obj, dict) and "name" in obj: + name = obj["name"] + params = obj.get("parameters", obj.get("arguments", {})) + if isinstance(params, dict): + param_strs = [f"{k}={repr(v)}" for k, v in params.items()] + return f"{name}({', '.join(param_strs)})" + except (_json.JSONDecodeError, TypeError): + pass + return None + + +def _extract_calls_from_code(code: str) -> str | None: + """Extract function call expressions from Python code (skip imports, assignments).""" + import re + lines = code.strip().split('\n') + calls = [] + for line in lines: + stripped = line.strip() + # Skip imports, print, assignments with = + if stripped.startswith(("import ", "from ", "print(", "#", "def ", "return ")): + continue + # Look for variable = func(...) patterns + assign_match = re.match(r'^[a-zA-Z_]\w*\s*=\s*([a-zA-Z_]\w*(?:\.\w+)*\s*\(.*\))\s*$', stripped) + if assign_match: + calls.append(assign_match.group(1)) + continue + # Look for bare function calls + if re.match(r'^[a-zA-Z_]\w*(?:\.\w+)*\s*\(', stripped): + calls.append(stripped) + if calls: + if len(calls) == 1: + return calls[0] + return '[' + ', '.join(calls) + ']' + return None + + +def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> EvalOutputItem: + """Evaluate a single BFCL item using ast_checker.""" + from bfcl.eval_checker.ast_eval.ast_checker import ast_checker + from bfcl.model_handler.utils import default_decode_ast_prompting + + if item.output_obj is None: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": "No workflow output (output_obj is None)"}, + ) + + # Parse the test entry and ground truth + try: + entry = json.loads(item.input_obj) if isinstance(item.input_obj, str) else item.input_obj + answer = json.loads(item.expected_output_obj) if isinstance(item.expected_output_obj, str) else item.expected_output_obj + except (json.JSONDecodeError, TypeError) as e: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": f"Failed to parse input/answer: {e}"}, + ) + + func_description = entry.get("function", []) + possible_answer = answer.get("ground_truth", []) + model_output_raw = _extract_function_call(item.output_obj) + + # Handle irrelevance/relevance tests differently + if "irrelevance" in test_category: + # For irrelevance: model should NOT produce a valid function call + try: + decoded = default_decode_ast_prompting(model_output_raw, language) + # If decoding succeeds and produces non-empty output, it's a failure + if decoded and any(decoded): + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": "Model produced function call for irrelevance test", + "decoded": str(decoded)}, + ) + except Exception: + pass # Decode failure = success for irrelevance + return EvalOutputItem(id=item.id, score=1.0, reasoning={"status": "correct_irrelevance"}) + + if "relevance" in test_category: + # For relevance: model should produce a valid function call (any) + try: + decoded = default_decode_ast_prompting(model_output_raw, language) + if decoded and any(decoded): + return EvalOutputItem(id=item.id, score=1.0, reasoning={"status": "correct_relevance"}) + except Exception: + pass + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": "Model failed to produce function call for relevance test"}, + ) + + # Standard AST evaluation: decode and check + try: + decoded_output = default_decode_ast_prompting(model_output_raw, language) + except Exception as e: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": f"AST decode failed: {e}", "raw_output": model_output_raw[:500]}, + ) + + try: + checker_result = ast_checker( + func_description, decoded_output, possible_answer, + language, test_category, "nat_benchmark", + ) + except Exception as e: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": f"ast_checker failed: {e}", "decoded": str(decoded_output)[:500]}, + ) + + is_valid = checker_result.get("valid", False) + score = 1.0 if is_valid else 0.0 + reasoning = { + "valid": is_valid, + "raw_output": model_output_raw[:500], + "decoded": str(decoded_output)[:500], + } + if not is_valid: + reasoning["error"] = checker_result.get("error", []) + reasoning["error_type"] = checker_result.get("error_type", "unknown") + + return EvalOutputItem(id=item.id, score=score, reasoning=reasoning) + + +@register_evaluator(config_type=BFCLEvaluatorConfig) +async def bfcl_evaluator_function(config: BFCLEvaluatorConfig, builder: EvalBuilder): + + async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: + eval_output_items = [] + + for item in eval_input.eval_input_items: + try: + output_item = _evaluate_single(item, config.test_category, config.language) + except Exception as e: + logger.exception("Error evaluating BFCL item %s: %s", item.id, e) + output_item = EvalOutputItem( + id=item.id, score=0.0, reasoning={"error": str(e)}, + ) + eval_output_items.append(output_item) + + scores = [i.score for i in eval_output_items if isinstance(i.score, (int, float))] + average_score = sum(scores) / len(scores) if scores else 0.0 + + logger.info( + "BFCL evaluation complete: accuracy=%.3f (%d/%d) category=%s", + average_score, sum(1 for s in scores if s == 1.0), len(scores), config.test_category, + ) + + return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) + + yield EvaluatorInfo( + config=config, + evaluate_fn=evaluate_fn, + description=f"BFCL AST evaluator (category: {config.test_category})", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py new file mode 100644 index 0000000000..fccfc15803 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py @@ -0,0 +1,274 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +""" +Tool Intent Stub System for Decision-Only Evaluation. + +This module provides a mechanism to capture tool-intent decisions without executing actual tools. +Each stub: +1. Reads expected parameters from the tool schema +2. Records the invocation (tool_name, parameters) to a shared buffer +3. Returns a canned response so the agent continues reasoning +""" + +import contextvars +import json +import logging +from typing import Any + +from pydantic import BaseModel +from pydantic import field_validator + +logger = logging.getLogger(__name__) + +# Global registry for tool intents (accessible across module) +# This allows evaluators to retrieve captured intents +_GLOBAL_INTENT_REGISTRY: dict[str, list[dict[str, Any]]] = {} + +# Context variable for current scenario ID (async-safe for concurrent execution isolation) +# Unlike threading.local(), contextvars work correctly with asyncio tasks +_current_scenario_id: contextvars.ContextVar[str] = contextvars.ContextVar("scenario_id", default="current") + + +def set_current_scenario_id(scenario_id: str) -> contextvars.Token: + """ + Set the current scenario ID for this async context. + + This allows concurrent async workflows to isolate their intents. + Call this before executing a workflow to ensure intents are recorded + to the correct scenario. + + Args: + scenario_id: Unique identifier for the current scenario/question + + Returns: + Token that can be used to reset the scenario ID (for cleanup) + """ + token = _current_scenario_id.set(scenario_id) + # Initialize registry entry if needed + if scenario_id not in _GLOBAL_INTENT_REGISTRY: + _GLOBAL_INTENT_REGISTRY[scenario_id] = [] + logger.debug("Set current scenario ID to: %s", scenario_id) + return token + + +def get_current_scenario_id() -> str: + """ + Get the current scenario ID for this async context. + + Returns: + The current scenario ID, or "current" if not set + """ + return _current_scenario_id.get() + + +class ToolIntentBuffer: + """ + Shared buffer to store tool intent captures during agent execution. + + This is used in decision-only mode to track which tools the agent + decided to call and with what parameters, without actually executing them. + + Uses a global registry so evaluators can access intents across the codebase. + The buffer uses the current scenario ID from the contextvar (set via + set_current_scenario_id) for both recording and clearing intents. + """ + + def __init__(self) -> None: + """Initialize a tool intent buffer.""" + self.intents: list[dict[str, Any]] = [] + + def record(self, tool_name: str, parameters: dict[str, Any]) -> None: + """ + Record a tool intent. + + Args: + tool_name: Name of the tool the agent decided to call + parameters: Parameters the agent provided for the tool call + """ + intent = {"tool": tool_name, "parameters": parameters} + self.intents.append(intent) + + # Store in global registry using contextvar scenario ID for concurrent isolation + current_scenario = get_current_scenario_id() + if current_scenario not in _GLOBAL_INTENT_REGISTRY: + _GLOBAL_INTENT_REGISTRY[current_scenario] = [] + _GLOBAL_INTENT_REGISTRY[current_scenario].append(intent) + + logger.debug("Recorded tool intent: %s (scenario: %s)", tool_name, current_scenario) + + def get_intents(self) -> list[dict[str, Any]]: + """ + Get all recorded tool intents. + + Returns: + List of tool intents with format [{"tool": "name", "parameters": {...}}] + """ + return self.intents.copy() + + def clear(self) -> None: + """Clear all recorded intents for the current scenario.""" + self.intents.clear() + # Clear from global registry using contextvar (aligned with record()) + current_scenario = get_current_scenario_id() + _GLOBAL_INTENT_REGISTRY[current_scenario] = [] + logger.debug("Cleared tool intent buffer for scenario %s", current_scenario) + + +def get_global_intents(scenario_id: str = "current") -> list[dict[str, Any]]: + """ + Retrieve tool intents from the global registry. + + This allows evaluators to access intents without needing builder access. + + Args: + scenario_id: Identifier for the scenario + + Returns: + List of tool intents + """ + return _GLOBAL_INTENT_REGISTRY.get(scenario_id, []).copy() + + +def clear_global_intents(scenario_id: str = "current") -> None: + """ + Clear intents from global registry. + + Args: + scenario_id: Identifier for the scenario to clear + """ + if scenario_id in _GLOBAL_INTENT_REGISTRY: + _GLOBAL_INTENT_REGISTRY[scenario_id] = [] + logger.debug("Cleared global intents for scenario %s", scenario_id) + + +class PermissiveToolInput(BaseModel): + """ + Input schema that accepts tool parameters as either dict or JSON string. + + This handles the case where LangChain sometimes serializes tool inputs + as JSON strings before passing them to the tool, while NAT expects dicts. + """ + input_params: dict[str, Any] | str + + @field_validator('input_params', mode='before') + @classmethod + def parse_string_to_dict(cls, v: Any) -> dict[str, Any]: + """Convert JSON string to dict if needed.""" + if isinstance(v, str): + try: + # Handle both single and double quotes in JSON strings + normalized = v.replace("'", '"') + return json.loads(normalized) + except json.JSONDecodeError: + logger.warning("Failed to parse input_params string as JSON: %s", v[:100]) + return {} + elif isinstance(v, dict): + return v + else: + logger.warning("Unexpected input_params type: %s", type(v)) + return {} + + +def create_tool_stub_function(tool_schema: dict[str, Any], + intent_buffer: ToolIntentBuffer, + canned_response: str | None = None) -> tuple[callable, BaseModel | None, str]: + """ + Create a stub function for a tool that captures intent without executing. + + Args: + tool_schema: Tool schema from the dataset (includes title, description, properties, required) + intent_buffer: Shared buffer to record tool intents + canned_response: Optional canned response to return (defaults to success message) + + Returns: + Tuple of (async_function, input_schema, function_description) + Note: Returns custom input_schema with no validation to accept any parameter format + """ + tool_name = tool_schema.get("title", "unknown_tool") + tool_description = tool_schema.get("description", "") + + # Default canned response + if canned_response is None: + response_schema = tool_schema.get("response_schema", {}) + if response_schema: + # Generate a realistic-looking response based on schema + canned_response = json.dumps(_generate_mock_response(response_schema), indent=2) + else: + canned_response = f"Successfully executed {tool_name}. Operation completed." + + # Create stub function that accepts object input (broadest concrete type) + # The PermissiveToolInput validator will handle string-to-dict conversion + async def tool_stub_fn(input_params: object) -> str: + """Tool stub that captures intent without executing.""" + # At this point, input_params should be a dict thanks to the Pydantic validator + # Handle nested 'params' dict from LangChain if present + if isinstance(input_params, dict): + if 'params' in input_params and isinstance(input_params['params'], dict): + params_dict = input_params['params'] + else: + params_dict = input_params + else: + # Fallback in case validation didn't run + logger.warning("input_params is not a dict: %s", type(input_params)) + params_dict = {} + + # Filter out None values + if isinstance(params_dict, dict): + params_dict = {k: v for k, v in params_dict.items() if v is not None} + intent_buffer.record(tool_name, params_dict) + logger.info("Tool stub executed: %s with %d parameters", tool_name, len(params_dict)) + return canned_response + + # Set proper attributes + tool_stub_fn.__name__ = tool_name + tool_stub_fn.__doc__ = tool_description + + # Return function WITH custom input_schema that accepts both dict and string + return tool_stub_fn, PermissiveToolInput, tool_description + + +def _generate_mock_response(response_schema: dict[str, Any]) -> dict[str, Any]: + """ + Generate a mock response based on the response schema. + + Args: + response_schema: Response schema from the tool definition + + Returns: + Dictionary with mock values matching the schema + """ + mock_response = {} + properties = response_schema.get("properties", {}) + + for prop_name, prop_info in properties.items(): + prop_type = prop_info.get("type", "string") + + # Generate mock values based on type + if prop_type == "string": + mock_response[prop_name] = f"mock_{prop_name}" + elif prop_type == "integer": + mock_response[prop_name] = 100 + elif prop_type == "number": + mock_response[prop_name] = 100.50 + elif prop_type == "boolean": + mock_response[prop_name] = True + elif prop_type == "array": + mock_response[prop_name] = [] + elif prop_type == "object": + mock_response[prop_name] = {} + else: + mock_response[prop_name] = None + + return mock_response diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py new file mode 100644 index 0000000000..cf275e3469 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BFCL AST (prompting) workflow. + +Serializes function schemas as text in the system prompt and makes a single +LLM call. The model outputs raw function call text (e.g. `func(param=val)`) +which BFCL's ast_checker can parse. +""" + +import json +import logging + +from nat.builder.builder import Builder +from nat.builder.framework_enum import LLMFrameworkEnum +from nat.builder.function_info import FunctionInfo +from nat.cli.register_workflow import register_function + +from .config import BFCLASTWorkflowConfig + +logger = logging.getLogger(__name__) + +# System prompt matching BFCL's default AST prompting format +# Source: bfcl.model_handler.constant.DEFAULT_SYSTEM_PROMPT +SYSTEM_PROMPT = """You are an expert in composing functions. You are given a question and a set of possible functions. Based on the question, you will need to make one or more function/tool calls to achieve the purpose. +If none of the functions can be used, point it out. If the given question lacks the parameters required by the function, also point it out. +You should only return the function calls in your response. + +If you decide to invoke any of the function(s), you MUST put it in the format of [func_name1(params_name1=params_value1, params_name2=params_value2...), func_name2(params)] +You SHOULD NOT include any other text in the response. + +Here is a list of functions in JSON format that you can invoke. +{functions_json} +""" + + +@register_function(config_type=BFCLASTWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) +async def bfcl_ast_workflow(config: BFCLASTWorkflowConfig, builder: Builder): + from langchain_core.messages import HumanMessage, SystemMessage + + llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) + + async def _run(input_json: str) -> str: + """Single-turn AST prompting: serialize schemas into prompt, return raw text.""" + entry = json.loads(input_json) + functions = entry.get("function", []) + question_turns = entry.get("question", [[]]) + + # Build system message with function schemas + functions_json = json.dumps(functions, indent=2) + system_msg = SystemMessage(content=SYSTEM_PROMPT.format(functions_json=functions_json)) + + # Build user message(s) — BFCL uses the last turn's last message + user_content = "" + for turn in question_turns: + for msg in turn: + if msg.get("role") == "user": + user_content = msg["content"] + + messages = [system_msg, HumanMessage(content=user_content)] + response = await llm.ainvoke(messages) + return str(response.content) + + yield FunctionInfo.from_fn(_run, description=config.description) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py new file mode 100644 index 0000000000..24ff7e1409 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py @@ -0,0 +1,106 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BFCL Native FC workflow. + +Uses llm.bind_tools(schemas) + ainvoke() to make the LLM produce structured +tool_calls via the native function calling API. Extracts tool_calls from +AIMessage and formats them for BFCL's ast_checker. +""" + +import json +import logging + +from nat.builder.builder import Builder +from nat.builder.framework_enum import LLMFrameworkEnum +from nat.builder.function_info import FunctionInfo +from nat.cli.register_workflow import register_function + +from .config import BFCLFCWorkflowConfig + +logger = logging.getLogger(__name__) + +# Map BFCL type names to OpenAPI/JSON Schema types +GORILLA_TO_OPENAPI = { + "integer": "integer", + "number": "number", + "float": "number", + "string": "string", + "boolean": "boolean", + "array": "array", + "dict": "object", + "object": "object", + "tuple": "array", + "any": "string", + "String": "string", + "int": "integer", +} + + +def _convert_bfcl_schema_to_openai(func: dict) -> dict: + """Convert a BFCL function schema to OpenAI function calling format.""" + params = func.get("parameters", {}) + properties = {} + for name, prop in params.get("properties", {}).items(): + converted = dict(prop) + if "type" in converted: + converted["type"] = GORILLA_TO_OPENAPI.get(converted["type"], converted["type"]) + properties[name] = converted + + return { + "type": "function", + "function": { + "name": func["name"], + "description": func.get("description", ""), + "parameters": { + "type": "object", + "properties": properties, + "required": params.get("required", []), + }, + }, + } + + +@register_function(config_type=BFCLFCWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) +async def bfcl_fc_workflow(config: BFCLFCWorkflowConfig, builder: Builder): + from langchain_core.messages import HumanMessage + + llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) + + async def _run(input_json: str) -> str: + """Single-turn FC: bind tools, call LLM, extract tool_calls.""" + entry = json.loads(input_json) + functions = entry.get("function", []) + question_turns = entry.get("question", [[]]) + + # Convert BFCL schemas to OpenAI tool format + tools = [_convert_bfcl_schema_to_openai(f) for f in functions] + bound_llm = llm.bind_tools(tools) + + # Get user message + user_content = "" + for turn in question_turns: + for msg in turn: + if msg.get("role") == "user": + user_content = msg["content"] + + response = await bound_llm.ainvoke([HumanMessage(content=user_content)]) + + if not response.tool_calls: + # No tool calls — return empty (will be scored as failure for non-irrelevance tests) + return str(response.content) + + # Format tool calls as BFCL expects: + # List of function call strings like: func_name(param1=val1, param2=val2) + call_strs = [] + for tc in response.tool_calls: + name = tc["name"] + args = tc["args"] + # Format as Python function call string for AST parsing + param_strs = [] + for k, v in args.items(): + param_strs.append(f"{k}={repr(v)}") + call_strs.append(f"{name}({', '.join(param_strs)})") + + return "[" + ", ".join(call_strs) + "]" + + yield FunctionInfo.from_fn(_run, description=config.description) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py new file mode 100644 index 0000000000..52a6e1a6a3 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py @@ -0,0 +1,165 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BFCL ReAct workflow. + +Drives a ReAct-style tool-calling loop using NAT's LLM with bind_tools(). +Tool calls are captured via ToolIntentBuffer and formatted as BFCL-compatible +AST output for scoring. This demonstrates NAT-native agent execution against +BFCL benchmarks — the agent reasons step-by-step before making tool calls, +and tool stubs return canned responses so the agent can continue reasoning. +""" + +import hashlib +import json +import logging + +from pydantic import Field + +from nat.builder.builder import Builder +from nat.builder.framework_enum import LLMFrameworkEnum +from nat.builder.function_info import FunctionInfo +from nat.cli.register_workflow import register_function +from nat.data_models.agent import AgentBaseConfig + +from .tool_intent_stubs import ToolIntentBuffer, set_current_scenario_id, clear_global_intents +from .workflow_fc import _convert_bfcl_schema_to_openai, GORILLA_TO_OPENAPI + +logger = logging.getLogger(__name__) + + +class BFCLReActWorkflowConfig(AgentBaseConfig, name="bfcl_react_workflow"): + """Workflow config for BFCL ReAct evaluation. + + Uses a ReAct-style loop: the LLM reasons, calls tools (stubs), observes + results, and continues until it produces a final answer or reaches max steps. + Tool call intents are captured for BFCL scoring. + """ + + description: str = Field(default="BFCL ReAct Workflow") + max_steps: int = Field( + default=5, + description="Maximum number of ReAct reasoning/action steps per item", + ) + + +@register_function(config_type=BFCLReActWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) +async def bfcl_react_workflow(config: BFCLReActWorkflowConfig, builder: Builder): + from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage + + llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) + + async def _run(input_json: str) -> str: + """ReAct loop: reason → call tool stubs → observe → repeat → output intents.""" + entry = json.loads(input_json) + functions = entry.get("function", []) + question_turns = entry.get("question", [[]]) + + # Set up scenario isolation for concurrent execution + scenario_id = f"bfcl_{hashlib.md5(input_json[:200].encode()).hexdigest()[:12]}" + token = set_current_scenario_id(scenario_id) + clear_global_intents(scenario_id) + intent_buffer = ToolIntentBuffer() + + try: + # Convert BFCL schemas to OpenAI tool format + tools = [_convert_bfcl_schema_to_openai(f) for f in functions] + bound_llm = llm.bind_tools(tools) + + # Build type map for coercing args to expected types + param_types = {} # {func_name: {param_name: bfcl_type}} + for f in functions: + props = f.get("parameters", {}).get("properties", {}) + param_types[f["name"]] = {k: v.get("type", "string") for k, v in props.items()} + + # Get user message + user_content = "" + for turn in question_turns: + for msg in turn: + if msg.get("role") == "user": + user_content = msg["content"] + + # Build initial messages + system_msg = SystemMessage( + content="You are a helpful assistant. Use the provided tools to answer the user's request. " + "Think step by step about which tool(s) to call and with what parameters." + ) + messages = [system_msg, HumanMessage(content=user_content)] + + # ReAct loop + for step in range(config.max_steps): + response = await bound_llm.ainvoke(messages) + + if not response.tool_calls: + # Agent decided it's done — no more tool calls + break + + # Process all tool calls in this step + for tc in response.tool_calls: + name = tc["name"] + args = dict(tc["args"]) + + # Coerce args to expected types from BFCL schema + types = param_types.get(name, {}) + for k, v in args.items(): + expected = types.get(k, "string") + if expected in ("integer", "int") and isinstance(v, str): + try: + args[k] = int(v) + except ValueError: + pass + elif expected in ("float", "number") and isinstance(v, str): + try: + args[k] = float(v) + except ValueError: + pass + elif expected == "boolean" and isinstance(v, str): + args[k] = v.lower() in ("true", "1", "yes") + + # Record intent + intent_buffer.record(name, args) + + # Return canned response so the agent can continue + canned = f"Successfully executed {name}. Operation completed." + + # Add the assistant message with tool call + tool response + messages.append(AIMessage( + content="", + tool_calls=[{ + "name": name, + "args": args, + "id": tc.get("id", f"call_{step}_{name}"), + }], + )) + messages.append(ToolMessage( + content=canned, + tool_call_id=tc.get("id", f"call_{step}_{name}"), + )) + + # Format captured intents as BFCL-compatible output + intents = intent_buffer.get_intents() + if not intents: + return "" + + # Deduplicate intents (same tool + same params = single call) + seen = set() + unique_intents = [] + for intent in intents: + key = (intent["tool"], json.dumps(intent["parameters"], sort_keys=True)) + if key not in seen: + seen.add(key) + unique_intents.append(intent) + + # Format as Python function call strings for AST parsing + call_strs = [] + for intent in unique_intents: + name = intent["tool"] + params = intent["parameters"] + param_strs = [f"{k}={repr(v)}" for k, v in params.items()] + call_strs.append(f"{name}({', '.join(param_strs)})") + + return "[" + ", ".join(call_strs) + "]" + + finally: + clear_global_intents(scenario_id) + + yield FunctionInfo.from_fn(_run, description=config.description) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py new file mode 100644 index 0000000000..ad64ecd840 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Configuration types for BYOB (Bring Your Own Benchmark) integration.""" + +from collections.abc import Callable +from typing import Any + +from pydantic import Field + +from nat.data_models.dataset_handler import EvalDatasetBaseConfig +from nat.data_models.evaluator import EvaluatorBaseConfig + + +class BYOBDatasetConfig(EvalDatasetBaseConfig, name="byob"): + """Dataset config for BYOB benchmarks. + + Loads a dataset from a BYOB benchmark definition. The benchmark module + and name are used to import the benchmark and access its dataset. + """ + + benchmark_module: str = Field( + description="Python module path or file path to the benchmark definition " + "(e.g. 'my_benchmarks.qa' or '/path/to/benchmark.py')", + ) + benchmark_name: str = Field( + description="Normalized benchmark name as registered with @benchmark decorator", + ) + limit: int | None = Field( + default=None, + description="Limit number of dataset samples (for testing)", + ) + + def parser(self) -> tuple[Callable, dict]: + from .dataset import load_byob_dataset + return load_byob_dataset, { + "benchmark_module": self.benchmark_module, + "benchmark_name": self.benchmark_name, + "limit": self.limit, + } + + +class BYOBEvaluatorConfig(EvaluatorBaseConfig, name="byob_evaluator"): + """Evaluator config for BYOB benchmarks. + + Calls bench.scorer_fn(ScorerInput(...)) directly; model_call_fn=None + (safe for all built-in scorers like exact_match, contains, f1_token). + """ + + benchmark_module: str = Field( + description="Python module path or file path to the benchmark definition", + ) + benchmark_name: str = Field( + description="Normalized benchmark name", + ) + score_field: str = Field( + default="correct", + description="Key in scorer output dict to use as the primary score " + "(e.g. 'correct' for exact_match, 'f1' for f1_token)", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py new file mode 100644 index 0000000000..0151dac255 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py @@ -0,0 +1,72 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BYOB dataset loader. + +Imports a BYOB benchmark definition and loads its dataset into a DataFrame +compatible with NAT's eval runner. +""" + +import json +import logging +from pathlib import Path + +import pandas as pd + +from nat.builder.builder import EvalBuilder +from nat.builder.dataset_loader import DatasetLoaderInfo +from nat.cli.register_workflow import register_dataset_loader + +from .config import BYOBDatasetConfig + +logger = logging.getLogger(__name__) + + +def load_byob_dataset( + file_path: str | Path, + benchmark_module: str = "", + benchmark_name: str = "", + limit: int | None = None, +) -> pd.DataFrame: + """Load a BYOB benchmark's dataset into a DataFrame. + + Uses import_benchmark() to resolve the benchmark definition, then loads + the dataset using BYOB's dataset loading utilities. + + The file_path parameter is required by NAT's DatasetHandler interface but + is ignored — the dataset path comes from the benchmark definition. + """ + from nemo_evaluator.contrib.byob.eval_logic import import_benchmark + from nemo_evaluator.contrib.byob.dataset import load_dataset + + bench = import_benchmark(benchmark_module, benchmark_name) + logger.info("Imported BYOB benchmark '%s' (dataset: %s)", bench.name, bench.dataset) + + # Load the raw dataset + samples = load_dataset(bench.dataset, limit=limit, field_mapping=bench.field_mapping) + + rows = [] + for i, sample in enumerate(samples): + target = sample.get(bench.target_field, "") + # Use response_field for eval-only mode if present + response = sample.get(bench.response_field, "") if bench.response_field else "" + + rows.append({ + "id": sample.get("id", str(i)), + "question": json.dumps(sample), + "answer": json.dumps(target) if not isinstance(target, str) else target, + }) + + logger.info("Loaded %d BYOB samples from benchmark '%s'", len(rows), bench.name) + return pd.DataFrame(rows) + + +@register_dataset_loader(config_type=BYOBDatasetConfig) +async def register_byob_dataset_loader(config: BYOBDatasetConfig, builder: EvalBuilder): + yield DatasetLoaderInfo( + config=config, + load_fn=lambda fp, **kw: load_byob_dataset( + fp, benchmark_module=config.benchmark_module, + benchmark_name=config.benchmark_name, limit=config.limit, **kw, + ), + description="BYOB benchmark dataset loader", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py new file mode 100644 index 0000000000..be508aa186 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py @@ -0,0 +1,120 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""BYOB benchmark evaluator. + +Calls bench.scorer_fn(ScorerInput(...)) directly in-process. +model_call_fn=None is safe for all built-in scorers (exact_match, contains, +f1_token, bleu, rouge, regex_match). +""" + +import json +import logging + +from nat.builder.builder import EvalBuilder +from nat.builder.evaluator import EvaluatorInfo +from nat.cli.register_workflow import register_evaluator +from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem + +from .config import BYOBEvaluatorConfig + +logger = logging.getLogger(__name__) + + +def _evaluate_single( + item: EvalInputItem, + scorer_fn, + target_field: str, + score_field: str, + extra_config: dict, +) -> EvalOutputItem: + """Evaluate a single item using the BYOB scorer.""" + from nemo_evaluator.contrib.byob.decorators import ScorerInput + + if item.output_obj is None: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": "No workflow output (output_obj is None)"}, + ) + + # Reconstruct metadata from the full dataset entry + if isinstance(item.full_dataset_entry, str): + try: + metadata = json.loads(item.full_dataset_entry) + except (json.JSONDecodeError, TypeError): + metadata = {} + elif isinstance(item.full_dataset_entry, dict): + metadata = item.full_dataset_entry + else: + metadata = {} + + # Get target value + target = item.expected_output_obj + if isinstance(target, str): + try: + target = json.loads(target) + except (json.JSONDecodeError, ValueError): + pass # Keep as string + + scorer_input = ScorerInput( + response=str(item.output_obj), + target=target, + metadata=metadata, + model_call_fn=None, + config=extra_config, + ) + + try: + scores = scorer_fn(scorer_input) + except Exception as e: + return EvalOutputItem( + id=item.id, score=0.0, + reasoning={"error": f"Scorer failed: {e}"}, + ) + + # Extract the primary score + primary_score = scores.get(score_field, 0.0) + if isinstance(primary_score, bool): + primary_score = 1.0 if primary_score else 0.0 + + return EvalOutputItem(id=item.id, score=float(primary_score), reasoning=scores) + + +@register_evaluator(config_type=BYOBEvaluatorConfig) +async def byob_evaluator_function(config: BYOBEvaluatorConfig, builder: EvalBuilder): + from nemo_evaluator.contrib.byob.eval_logic import import_benchmark + + bench = import_benchmark(config.benchmark_module, config.benchmark_name) + logger.info("BYOB evaluator loaded benchmark '%s' with scorer '%s'", + bench.name, getattr(bench.scorer_fn, '__name__', 'unknown')) + + async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: + eval_output_items = [] + + for item in eval_input.eval_input_items: + try: + output_item = _evaluate_single( + item, bench.scorer_fn, bench.target_field, + config.score_field, bench.extra_config, + ) + except Exception as e: + logger.exception("Error evaluating BYOB item %s: %s", item.id, e) + output_item = EvalOutputItem( + id=item.id, score=0.0, reasoning={"error": str(e)}, + ) + eval_output_items.append(output_item) + + scores = [i.score for i in eval_output_items if isinstance(i.score, (int, float))] + average_score = sum(scores) / len(scores) if scores else 0.0 + + logger.info( + "BYOB evaluation complete: avg_%s=%.3f (%d items)", + config.score_field, average_score, len(scores), + ) + + return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) + + yield EvaluatorInfo( + config=config, + evaluate_fn=evaluate_fn, + description=f"BYOB evaluator for '{config.benchmark_name}'", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py new file mode 100644 index 0000000000..5059d73b91 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# flake8: noqa + +# ToolTalk benchmark components +from .tooltalk.dataset import register_tooltalk_dataset_loader +from .tooltalk.evaluator import tooltalk_evaluator_function +from .tooltalk.workflow import tooltalk_workflow + +# BFCL benchmark components +from .bfcl.dataset import register_bfcl_dataset_loader +from .bfcl.evaluator import bfcl_evaluator_function +from .bfcl.workflow_ast import bfcl_ast_workflow +from .bfcl.workflow_fc import bfcl_fc_workflow +from .bfcl.workflow_react import bfcl_react_workflow + +# BYOB benchmark components +from .byob.dataset import register_byob_dataset_loader +from .byob.evaluator import byob_evaluator_function + +# Agent Leaderboard v2 benchmark components +from .agent_leaderboard.dataset import register_agent_leaderboard_dataset_loader +from .agent_leaderboard.evaluator import agent_leaderboard_tsq_evaluator +from .agent_leaderboard.workflow import agent_leaderboard_workflow diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py new file mode 100644 index 0000000000..3bdbc77bfd --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +from collections.abc import Callable +from pathlib import Path + +from pydantic import Field + +from nat.data_models.agent import AgentBaseConfig +from nat.data_models.dataset_handler import EvalDatasetBaseConfig +from nat.data_models.evaluator import EvaluatorBaseConfig + + +class ToolTalkDatasetConfig(EvalDatasetBaseConfig, name="tooltalk"): + """Dataset config for ToolTalk benchmark. + + file_path should point to a ToolTalk data directory (e.g. tooltalk/data/easy/) + containing one JSON file per conversation. + """ + + database_dir: str = Field( + description="Path to ToolTalk database directory (contains Account.json, Alarm.json, etc.)", + ) + + def parser(self) -> tuple[Callable, dict]: + from .dataset import load_tooltalk_dataset + return load_tooltalk_dataset, {} + + +class ToolTalkWorkflowConfig(AgentBaseConfig, name="tooltalk_workflow"): + """Workflow config for ToolTalk benchmark. + + Runs multi-turn conversations using NAT's LLM with ToolTalk's simulated tool backends. + """ + + description: str = Field(default="ToolTalk Benchmark Workflow") + database_dir: str = Field( + description="Path to ToolTalk database directory", + ) + api_mode: str = Field( + default="all", + description="Which API docs to include: 'exact' (only APIs in conversation), " + "'suite' (all APIs in used suites), or 'all'", + ) + disable_documentation: bool = Field( + default=False, + description="If True, send empty descriptions in tool schemas", + ) + max_tool_calls_per_turn: int = Field( + default=10, + description="Maximum tool calls per assistant turn before forcing a text response", + ) + + +class ToolTalkEvaluatorConfig(EvaluatorBaseConfig, name="tooltalk_evaluator"): + """Evaluator config for ToolTalk benchmark. + + Uses ToolTalk's built-in metrics: recall, action_precision, bad_action_rate, success. + """ + + database_dir: str = Field( + description="Path to ToolTalk database directory", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py new file mode 100644 index 0000000000..ab2219a143 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py @@ -0,0 +1,54 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import json +import logging +from pathlib import Path + +import pandas as pd + +from nat.builder.builder import EvalBuilder +from nat.builder.dataset_loader import DatasetLoaderInfo +from nat.cli.register_workflow import register_dataset_loader + +from .config import ToolTalkDatasetConfig + +logger = logging.getLogger(__name__) + + +def load_tooltalk_dataset(file_path: str | Path) -> pd.DataFrame: + """Load a ToolTalk dataset directory into a DataFrame. + + Each JSON file in the directory becomes one row. The full conversation JSON + is serialized into the 'question' column so the workflow can deserialize it. + The ground truth conversation (with expected API calls) goes into 'answer'. + """ + data_dir = Path(file_path) + if not data_dir.is_dir(): + raise ValueError(f"ToolTalk dataset path must be a directory, got: {file_path}") + + rows = [] + for json_file in sorted(data_dir.glob("*.json")): + with open(json_file, encoding="utf-8") as f: + conversation = json.load(f) + + rows.append({ + "id": conversation.get("conversation_id", json_file.stem), + "question": json.dumps(conversation), + "answer": json.dumps(conversation), + }) + + if not rows: + raise ValueError(f"No JSON files found in ToolTalk dataset directory: {file_path}") + + logger.info("Loaded %d ToolTalk conversations from %s", len(rows), data_dir) + return pd.DataFrame(rows) + + +@register_dataset_loader(config_type=ToolTalkDatasetConfig) +async def register_tooltalk_dataset_loader(config: ToolTalkDatasetConfig, builder: EvalBuilder): + yield DatasetLoaderInfo( + config=config, + load_fn=load_tooltalk_dataset, + description="ToolTalk benchmark dataset loader (directory of JSON conversations)", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py new file mode 100644 index 0000000000..1ad624f82f --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py @@ -0,0 +1,92 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""ToolTalk benchmark evaluator. + +Uses ToolTalk's built-in evaluation logic to compare predicted API calls against +ground truth, producing metrics: recall, action_precision, bad_action_rate, success. +""" + +import json +import logging + +from nat.builder.builder import EvalBuilder +from nat.builder.evaluator import EvaluatorInfo +from nat.cli.register_workflow import register_evaluator +from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem + +from .config import ToolTalkEvaluatorConfig + +logger = logging.getLogger(__name__) + + +@register_evaluator(config_type=ToolTalkEvaluatorConfig) +async def tooltalk_evaluator_function(config: ToolTalkEvaluatorConfig, builder: EvalBuilder): + from tooltalk.evaluation.tool_executor import ToolExecutor + + async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: + eval_output_items = [] + + for item in eval_input.eval_input_items: + try: + output_item = _evaluate_single(item, config.database_dir) + eval_output_items.append(output_item) + except Exception as e: + logger.exception("Error evaluating ToolTalk item %s: %s", item.id, e) + eval_output_items.append(EvalOutputItem( + id=item.id, + score=0.0, + reasoning={"error": str(e)}, + )) + + scores = [item.score for item in eval_output_items if isinstance(item.score, (int, float))] + average_score = sum(scores) / len(scores) if scores else 0.0 + + logger.info( + "ToolTalk evaluation complete: average_success=%.3f across %d conversations", + average_score, len(scores), + ) + + return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) + + yield EvaluatorInfo( + config=config, + evaluate_fn=evaluate_fn, + description="ToolTalk benchmark evaluator (recall, action_precision, success)", + ) + + +def _evaluate_single(item: EvalInputItem, database_dir: str) -> EvalOutputItem: + """Evaluate a single ToolTalk conversation using ToolTalk's built-in metrics.""" + from tooltalk.evaluation.tool_executor import ToolExecutor + + # output_obj contains the conversation JSON with predictions added by the workflow + if item.output_obj is None: + return EvalOutputItem( + id=item.id, + score=0.0, + reasoning={"error": "No workflow output (output_obj is None)"}, + ) + + conversation_with_predictions = json.loads(item.output_obj) + + # Use ToolTalk's ToolExecutor to compute metrics + tool_executor = ToolExecutor(init_database_dir=database_dir) + result = tool_executor.evaluate_predictions(conversation_with_predictions) + metrics = result.get("metrics", {}) + + success = float(metrics.get("success", 0.0)) + reasoning = { + "predictions": metrics.get("predictions", 0), + "ground_truths": metrics.get("ground_truths", 0), + "matches": metrics.get("matches", 0), + "recall": metrics.get("recall", 0.0), + "actions": metrics.get("actions", 0), + "valid_actions": metrics.get("valid_actions", 0), + "bad_actions": metrics.get("bad_actions", 0), + "action_precision": metrics.get("action_precision", 0.0), + "bad_action_rate": metrics.get("bad_action_rate", 0.0), + "success": success, + "soft_success": metrics.get("soft_success", 0.0), + } + + return EvalOutputItem(id=item.id, score=success, reasoning=reasoning) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py new file mode 100644 index 0000000000..78a3804678 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py @@ -0,0 +1,230 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""ToolTalk benchmark workflow. + +Replays multi-turn ToolTalk conversations using NAT's LLM with tool calling. +Tool calls are executed against ToolTalk's simulated database backends via ToolExecutor. +""" + +import json +import logging + +from nat.builder.builder import Builder +from nat.builder.framework_enum import LLMFrameworkEnum +from nat.builder.function_info import FunctionInfo +from nat.cli.register_workflow import register_function + +from .config import ToolTalkWorkflowConfig + +logger = logging.getLogger(__name__) + + +def _build_tool_schemas(apis_used, disable_docs: bool = False) -> list[dict]: + """Convert ToolTalk API classes to OpenAI function-calling tool schemas.""" + tools = [] + for api in apis_used: + doc = api.to_openai_doc(disable_docs) + required = doc.pop("required") + doc["parameters"]["required"] = required + tools.append({"type": "function", "function": doc}) + return tools + + +def _build_messages(conversation_history: list[dict], metadata: dict | None = None) -> list[dict]: + """Convert ToolTalk conversation history to OpenAI chat messages format.""" + system_prompt = ( + "You are a helpful assistant. Here is some user data:" + "\nlocation: {location}" + "\ntimestamp: {timestamp}" + "\nusername (if logged in): {username}" + ) + + messages = [] + if metadata: + messages.append({ + "role": "system", + "content": system_prompt.format( + location=metadata.get("location", "unknown"), + timestamp=metadata.get("timestamp", "unknown"), + username=metadata.get("username", "unknown"), + ), + }) + + tool_call_id_counter = 123456789 + for turn in conversation_history: + if turn["role"] in ("user", "assistant"): + messages.append({"role": turn["role"], "content": turn["text"]}) + elif turn["role"] == "api": + tool_call_id = str(tool_call_id_counter) + messages.append({ + "role": "assistant", + "content": "", + "tool_calls": [{ + "id": tool_call_id, + "type": "function", + "function": { + "name": turn["request"]["api_name"], + "arguments": json.dumps(turn["request"]["parameters"]), + }, + }], + }) + messages.append({ + "role": "tool", + "tool_call_id": tool_call_id, + "content": json.dumps({ + "response": turn["response"], + "exception": turn["exception"], + }), + }) + tool_call_id_counter += 1 + + return messages + + +@register_function(config_type=ToolTalkWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) +async def tooltalk_workflow(config: ToolTalkWorkflowConfig, builder: Builder): + from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage + + from tooltalk.apis import ALL_APIS, APIS_BY_NAME, SUITES_BY_NAME + from tooltalk.evaluation.tool_executor import ToolExecutor + + llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) + + async def _run_conversation(input_json: str) -> str: + """Run a ToolTalk conversation: replay user turns, predict tool calls, execute via ToolExecutor.""" + conversation = json.loads(input_json) + metadata = conversation["metadata"] + user_data = conversation.get("user") + + # Select APIs based on api_mode + if config.api_mode == "exact": + apis_used = [APIS_BY_NAME[name] for name in conversation["apis_used"]] + elif config.api_mode == "suite": + apis_used = [ + api + for suite_name in conversation["suites_used"] + for api in SUITES_BY_NAME[suite_name].apis + ] + else: + apis_used = ALL_APIS + + # Build OpenAI tool schemas and bind to LLM + tool_schemas = _build_tool_schemas(apis_used, config.disable_documentation) + bound_llm = llm.bind_tools(tool_schemas) + + # Fresh ToolExecutor per conversation + tool_executor = ToolExecutor(init_database_dir=config.database_dir) + + ground_truth_history = [] + api_history = [] + + for turn in conversation["conversation"]: + if turn["role"] == "user": + ground_truth_history.append({"role": "user", "text": turn["text"]}) + continue + + if turn["role"] != "assistant": + raise ValueError(f"Unexpected turn role: {turn['role']}") + + # Reset executor state for this turn's prediction + tool_executor.init_conversation_state(metadata, api_history, user_data) + predictions = [] + current_history = ground_truth_history.copy() + + # Prediction loop: call LLM, execute tool calls, repeat until assistant response + tool_call_count = 0 + while True: + messages = _build_messages(current_history, metadata) + + # Convert to LangChain message objects + lc_messages = [] + i = 0 + while i < len(messages): + msg = messages[i] + if msg["role"] == "system": + lc_messages.append(SystemMessage(content=msg["content"])) + elif msg["role"] == "user": + lc_messages.append(HumanMessage(content=msg["content"])) + elif msg["role"] == "assistant": + if "tool_calls" in msg and msg["tool_calls"]: + lc_messages.append(AIMessage( + content=msg.get("content", ""), + tool_calls=[{ + "name": tc["function"]["name"], + "args": json.loads(tc["function"]["arguments"]), + "id": tc["id"], + } for tc in msg["tool_calls"]], + )) + else: + lc_messages.append(AIMessage(content=msg["content"])) + elif msg["role"] == "tool": + lc_messages.append(ToolMessage( + content=msg["content"], + tool_call_id=msg["tool_call_id"], + )) + i += 1 + + # Call LLM + response = await bound_llm.ainvoke(lc_messages) + + if response.tool_calls: + # LLM made a tool call — execute it via ToolExecutor + tc = response.tool_calls[0] + api_name = tc["name"] + parameters = tc["args"] + + if parameters is None: + request = {"api_name": api_name, "parameters": None} + exec_response = {"response": None, "exception": "Failed to parse API call"} + else: + request, exec_response = tool_executor.execute_tool(api_name, parameters) + + prediction = { + "role": "api", + "request": request, + "response": exec_response["response"], + "exception": exec_response["exception"], + } + predictions.append(prediction) + tool_call_count += 1 + + # Guard against infinite tool-calling loops + if tool_call_count >= config.max_tool_calls_per_turn: + logger.warning( + "Reached max tool calls (%d) for turn, forcing text response", + config.max_tool_calls_per_turn, + ) + predictions.append({ + "role": "assistant", + "text": f"[max tool calls ({config.max_tool_calls_per_turn}) reached]", + }) + break + + # Add to history for next iteration + current_history.append(prediction) + else: + # LLM returned a text response — done with this turn + predictions.append({ + "role": "assistant", + "text": str(response.content), + }) + break + + # Store predictions on the turn + turn["predictions"] = predictions + + # Advance ground truth history + if "apis" in turn: + for api in turn["apis"]: + api_history.append(api) + ground_truth_history.append({ + "role": "api", + "request": api["request"], + "response": api["response"], + "exception": api["exception"], + }) + ground_truth_history.append({"role": "assistant", "text": turn["text"]}) + + return json.dumps(conversation) + + yield FunctionInfo.from_fn(_run_conversation, description=config.description) diff --git a/packages/nvidia_nat_benchmarks/tests/__init__.py b/packages/nvidia_nat_benchmarks/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py new file mode 100644 index 0000000000..731029f8bc --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py @@ -0,0 +1,141 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for Agent Leaderboard dataset loader — no network required for unit tests.""" + +import json +import os + +import pandas as pd +import pytest + +from nat.plugins.benchmarks.agent_leaderboard.dataset import ( + load_agent_leaderboard_dataset, + _derive_expected_tool_calls, +) + + +def _make_sample_tools(): + return [ + {"title": "get_account_balance", "description": "Get the balance of an account", "properties": {}, "required": []}, + {"title": "transfer_funds", "description": "Transfer money between accounts", "properties": {}, "required": []}, + {"title": "get_exchange_rates", "description": "Get currency exchange rates", "properties": {}, "required": []}, + {"title": "schedule_appointment", "description": "Schedule a branch appointment", "properties": {}, "required": []}, + ] + + +def _make_sample_entry(idx: int = 0, domain: str = "banking"): + tools = _make_sample_tools() + return { + "id": f"{domain}_scenario_{idx:03d}", + "question": "I need to check my balance and transfer some money", + "ground_truth": "User goals:\n- Check account balance\n- Transfer funds", + "user_goals": ["Check account balance", "Transfer funds"], + "available_tools": tools, + "expected_tool_calls": [ + {"tool": "get_account_balance", "parameters": {}}, + {"tool": "transfer_funds", "parameters": {}}, + ], + "metadata": {"domain": domain, "persona_name": "Test User", "num_goals": 2}, + } + + +class TestDeriveExpectedToolCalls: + + def test_matches_balance_goal(self): + tools = _make_sample_tools() + expected = _derive_expected_tool_calls(["Check my account balance"], tools) + tool_names = [tc["tool"] for tc in expected] + assert "get_account_balance" in tool_names + + def test_matches_transfer_goal(self): + tools = _make_sample_tools() + expected = _derive_expected_tool_calls(["Transfer money to savings"], tools) + tool_names = [tc["tool"] for tc in expected] + assert "transfer_funds" in tool_names + + def test_matches_exchange_goal(self): + tools = _make_sample_tools() + expected = _derive_expected_tool_calls(["What are the exchange rates?"], tools) + tool_names = [tc["tool"] for tc in expected] + assert "get_exchange_rates" in tool_names + + def test_no_match_returns_empty(self): + tools = _make_sample_tools() + expected = _derive_expected_tool_calls(["Tell me a joke"], tools) + assert expected == [] + + def test_deduplicates(self): + tools = _make_sample_tools() + expected = _derive_expected_tool_calls( + ["Check balance", "Also check my balance again"], tools + ) + tool_names = [tc["tool"] for tc in expected] + assert tool_names.count("get_account_balance") == 1 + + +class TestLoadFromFile: + + def test_loads_json_file(self, tmp_path): + """Loads pre-downloaded JSON file.""" + entries = [_make_sample_entry(i) for i in range(3)] + data_file = tmp_path / "test_data.json" + with open(data_file, "w") as f: + json.dump(entries, f) + + df = load_agent_leaderboard_dataset(str(data_file)) + assert len(df) == 3 + assert set(df.columns) >= {"id", "question", "answer"} + + def test_question_contains_full_entry(self, tmp_path): + entries = [_make_sample_entry()] + data_file = tmp_path / "test.json" + with open(data_file, "w") as f: + json.dump(entries, f) + + df = load_agent_leaderboard_dataset(str(data_file)) + loaded = json.loads(df.iloc[0]["question"]) + assert "available_tools" in loaded + assert "expected_tool_calls" in loaded + assert loaded["user_goals"] == ["Check account balance", "Transfer funds"] + + def test_limit_parameter(self, tmp_path): + entries = [_make_sample_entry(i) for i in range(10)] + data_file = tmp_path / "test.json" + with open(data_file, "w") as f: + json.dump(entries, f) + + df = load_agent_leaderboard_dataset(str(data_file), limit=3) + assert len(df) == 3 + + def test_answer_contains_expected_calls(self, tmp_path): + entries = [_make_sample_entry()] + data_file = tmp_path / "test.json" + with open(data_file, "w") as f: + json.dump(entries, f) + + df = load_agent_leaderboard_dataset(str(data_file)) + answer = json.loads(df.iloc[0]["answer"]) + assert len(answer) == 2 + assert answer[0]["tool"] == "get_account_balance" + + +class TestHuggingFaceDownload: + + @pytest.mark.integration + @pytest.mark.slow + def test_downloads_banking_domain(self): + """Downloads real data from HuggingFace — requires network.""" + try: + from datasets import load_dataset + except ImportError: + pytest.skip("datasets not installed") + + df = load_agent_leaderboard_dataset( + "/nonexistent/path.json", # Will trigger HF download + domains=["banking"], + limit=3, + ) + assert len(df) == 3 + entry = json.loads(df.iloc[0]["question"]) + assert "available_tools" in entry + assert entry["metadata"]["domain"] == "banking" diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py new file mode 100644 index 0000000000..6664190295 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py @@ -0,0 +1,148 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for the Agent Leaderboard TSQ evaluator — no LLM required.""" + +import json + +import pytest + +from nat.data_models.evaluator import EvalInputItem +from nat.plugins.benchmarks.agent_leaderboard.evaluator import _evaluate_single, _normalize_tool_name + + +def _make_entry(expected_tools: list[str], predicted_tools: list[str]) -> tuple[EvalInputItem, list]: + """Create a test item with expected and predicted tool calls.""" + expected_calls = [{"tool": t, "parameters": {}} for t in expected_tools] + predicted_calls = [{"tool": t, "parameters": {}} for t in predicted_tools] + + entry = { + "id": "test_001", + "question": "Do something", + "expected_tool_calls": expected_calls, + "available_tools": [], + } + + item = EvalInputItem( + id="test_001", + input_obj=json.dumps(entry), + expected_output_obj=json.dumps(expected_calls), + output_obj=json.dumps(predicted_calls), + full_dataset_entry=entry, + ) + return item + + +class TestNormalizeToolName: + + def test_basic(self): + assert _normalize_tool_name("get_account_balance") == "getaccountbalance" + + def test_with_prefix(self): + assert _normalize_tool_name("banking_tools__get_account_balance") == "getaccountbalance" + + def test_case_insensitive(self): + assert _normalize_tool_name("GetAccountBalance") == "getaccountbalance" + + def test_empty(self): + assert _normalize_tool_name("") == "" + + +class TestTSQEvaluator: + + def test_perfect_match(self): + """All predicted tools match expected → F1 = 1.0.""" + item = _make_entry( + expected_tools=["get_balance", "transfer_funds"], + predicted_tools=["get_balance", "transfer_funds"], + ) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + + assert result.score == 1.0 + assert result.reasoning["tool_selection_f1"] == 1.0 + + def test_partial_match(self): + """Only some tools match → 0 < F1 < 1.""" + item = _make_entry( + expected_tools=["get_balance", "transfer_funds", "get_history"], + predicted_tools=["get_balance", "check_loan"], + ) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + + assert 0.0 < result.score < 1.0 + + def test_no_match(self): + """No predicted tools match expected → F1 = 0.""" + item = _make_entry( + expected_tools=["get_balance"], + predicted_tools=["schedule_appointment"], + ) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + + assert result.score == 0.0 + + def test_no_predictions(self): + """No predictions when tools expected → score 0.""" + item = _make_entry( + expected_tools=["get_balance"], + predicted_tools=[], + ) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + + assert result.score == 0.0 + + def test_no_expected_no_predicted(self): + """No expected and no predicted → perfect score.""" + item = _make_entry(expected_tools=[], predicted_tools=[]) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + + assert result.score == 1.0 + + def test_extra_predictions_reduce_precision(self): + """Extra predicted tools reduce precision → lower F1.""" + item_exact = _make_entry( + expected_tools=["get_balance"], + predicted_tools=["get_balance"], + ) + item_extra = _make_entry( + expected_tools=["get_balance"], + predicted_tools=["get_balance", "extra_tool_1", "extra_tool_2"], + ) + + result_exact = _evaluate_single(item_exact, 1.0, 0.0) + result_extra = _evaluate_single(item_extra, 1.0, 0.0) + + assert result_exact.score > result_extra.score + + def test_none_output(self): + """None output → score 0.""" + entry = {"expected_tool_calls": [{"tool": "t", "parameters": {}}]} + item = EvalInputItem( + id="test", input_obj="{}", expected_output_obj="[]", + output_obj=None, full_dataset_entry=entry, + ) + result = _evaluate_single(item, 1.0, 0.0) + assert result.score == 0.0 + + def test_name_normalization_across_formats(self): + """Tool names with different formats should still match.""" + item = _make_entry( + expected_tools=["get_account_balance"], + predicted_tools=["GetAccountBalance"], + ) + result = _evaluate_single(item, 1.0, 0.0) + assert result.score == 1.0 + + +class TestTSQDatasetFormat: + + def test_handles_full_entry_as_string(self): + """full_dataset_entry can be a JSON string.""" + entry = {"expected_tool_calls": [{"tool": "get_balance", "parameters": {}}]} + item = EvalInputItem( + id="test", input_obj="{}", + expected_output_obj="[]", + output_obj=json.dumps([{"tool": "get_balance", "parameters": {}}]), + full_dataset_entry=json.dumps(entry), + ) + result = _evaluate_single(item, 1.0, 0.0) + assert result.score == 1.0 diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py b/packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py b/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py new file mode 100644 index 0000000000..732a3550f1 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Conftest for BFCL tests — mocks optional dependencies if missing.""" + +import sys +from unittest.mock import MagicMock + + +def _ensure_mock_module(name: str): + if name not in sys.modules: + try: + __import__(name) + except (ImportError, ModuleNotFoundError, TypeError): + sys.modules[name] = MagicMock() + + +# bfcl may try to import optional deps +_ensure_mock_module("torch") +_ensure_mock_module("transformers") +_ensure_mock_module("tree_sitter") +_ensure_mock_module("tree_sitter_java") +_ensure_mock_module("tree_sitter_javascript") diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py new file mode 100644 index 0000000000..88156fd815 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for the BFCL dataset loader — no LLM required.""" + +import json +import os + +import pandas as pd +import pytest + +from nat.plugins.benchmarks.bfcl.dataset import load_bfcl_dataset + + +def _make_bfcl_entry(entry_id: str, question: str = "Calculate area", func_name: str = "calc") -> dict: + return { + "id": entry_id, + "question": [[{"role": "user", "content": question}]], + "function": [{ + "name": func_name, + "description": "A test function", + "parameters": { + "type": "dict", + "properties": {"x": {"type": "integer", "description": "value"}}, + "required": ["x"], + }, + }], + } + + +def _make_bfcl_answer(entry_id: str) -> dict: + return { + "id": entry_id, + "ground_truth": [{"calc": {"x": [10]}}], + } + + +class TestBFCLDatasetLoader: + + def test_loads_jsonl_file(self, tmp_path): + """Each line in the JSONL becomes one DataFrame row.""" + test_file = tmp_path / "BFCL_v3_simple.json" + with open(test_file, "w") as f: + for i in range(3): + f.write(json.dumps(_make_bfcl_entry(f"simple_{i}")) + "\n") + + df = load_bfcl_dataset(str(test_file)) + assert len(df) == 3 + assert set(df.columns) >= {"id", "question", "answer"} + + def test_question_column_contains_full_entry(self, tmp_path): + test_file = tmp_path / "test.json" + with open(test_file, "w") as f: + f.write(json.dumps(_make_bfcl_entry("simple_0", "Find area")) + "\n") + + df = load_bfcl_dataset(str(test_file)) + loaded = json.loads(df.iloc[0]["question"]) + assert loaded["id"] == "simple_0" + assert loaded["function"][0]["name"] == "calc" + assert loaded["question"][0][0]["content"] == "Find area" + + def test_answer_column_contains_ground_truth(self, tmp_path): + """When possible_answer file exists, answers are loaded.""" + test_file = tmp_path / "BFCL_v3_simple.json" + answer_dir = tmp_path / "possible_answer" + answer_dir.mkdir() + answer_file = answer_dir / "BFCL_v3_simple.json" + + with open(test_file, "w") as f: + f.write(json.dumps(_make_bfcl_entry("simple_0")) + "\n") + with open(answer_file, "w") as f: + f.write(json.dumps(_make_bfcl_answer("simple_0")) + "\n") + + df = load_bfcl_dataset(str(test_file)) + answer = json.loads(df.iloc[0]["answer"]) + assert answer["ground_truth"] == [{"calc": {"x": [10]}}] + + def test_missing_answer_file_still_loads(self, tmp_path): + """Dataset loads even without possible_answer file.""" + test_file = tmp_path / "test.json" + with open(test_file, "w") as f: + f.write(json.dumps(_make_bfcl_entry("test_0")) + "\n") + + df = load_bfcl_dataset(str(test_file)) + assert len(df) == 1 + answer = json.loads(df.iloc[0]["answer"]) + assert answer["ground_truth"] == [] + + def test_raises_on_missing_file(self): + with pytest.raises(ValueError, match="not found"): + load_bfcl_dataset("/nonexistent/path.json") + + def test_loads_real_bfcl_simple_data(self): + """Smoke test against installed bfcl package data.""" + try: + from bfcl.constant import PROMPT_PATH + simple_file = os.path.join(PROMPT_PATH, "BFCL_v3_simple.json") + if not os.path.isfile(simple_file): + pytest.skip("BFCL simple data file not found") + except ImportError: + pytest.skip("bfcl not installed") + + df = load_bfcl_dataset(simple_file, test_category="simple") + assert len(df) > 0 + + # Verify structure + row = df.iloc[0] + entry = json.loads(row["question"]) + assert "function" in entry + assert "question" in entry diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py new file mode 100644 index 0000000000..80eee68081 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py @@ -0,0 +1,167 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for the BFCL evaluator — no LLM required. + +Uses pre-constructed model outputs to validate that ast_checker scoring works +correctly through the evaluator. +""" + +import json +import os + +import pytest + +from nat.data_models.evaluator import EvalInputItem + +try: + from bfcl.eval_checker.ast_eval.ast_checker import ast_checker + _HAS_BFCL = True +except ImportError: + _HAS_BFCL = False + +pytestmark = pytest.mark.skipif(not _HAS_BFCL, reason="bfcl not installed") + + +def _make_simple_entry() -> dict: + """BFCL simple test: calculate_triangle_area(base=10, height=5).""" + return { + "id": "simple_0", + "question": [[{"role": "user", "content": "Find area of triangle with base 10, height 5"}]], + "function": [{ + "name": "calculate_triangle_area", + "description": "Calculate the area of a triangle.", + "parameters": { + "type": "dict", + "properties": { + "base": {"type": "integer", "description": "The base"}, + "height": {"type": "integer", "description": "The height"}, + "unit": {"type": "string", "description": "Unit of measure"}, + }, + "required": ["base", "height"], + }, + }], + } + + +def _make_simple_answer() -> dict: + return { + "id": "simple_0", + "ground_truth": [{ + "calculate_triangle_area": { + "base": [10], + "height": [5], + "unit": ["units", ""], + }, + }], + } + + +def _make_eval_item(entry: dict, answer: dict, model_output: str) -> EvalInputItem: + return EvalInputItem( + id=entry["id"], + input_obj=json.dumps(entry), + expected_output_obj=json.dumps(answer), + output_obj=model_output, + full_dataset_entry=entry, + ) + + +class TestBFCLEvaluator: + + def test_correct_ast_output_scores_1(self): + """Model outputs correct function call text → score 1.0.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + model_output = "calculate_triangle_area(base=10, height=5)" + + item = _make_eval_item(entry, answer, model_output) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 1.0 + assert result.reasoning["valid"] is True + + def test_correct_with_optional_param(self): + """Model includes optional param with valid value → score 1.0.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + model_output = 'calculate_triangle_area(base=10, height=5, unit="units")' + + item = _make_eval_item(entry, answer, model_output) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 1.0 + + def test_wrong_param_value_scores_0(self): + """Wrong parameter value → score 0.0.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + model_output = "calculate_triangle_area(base=99, height=5)" + + item = _make_eval_item(entry, answer, model_output) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 0.0 + assert result.reasoning["valid"] is False + + def test_invalid_syntax_scores_0(self): + """Garbage output that can't be AST parsed → score 0.0.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + model_output = "I cannot do that, sorry." + + item = _make_eval_item(entry, answer, model_output) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 0.0 + + def test_none_output_scores_0(self): + """Null output → score 0.0.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + + item = _make_eval_item(entry, answer, None) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 0.0 + assert "error" in result.reasoning + + +class TestBFCLOutputFormatting: + """Test that workflow output formats are compatible with the evaluator.""" + + def test_fc_workflow_format_parseable(self): + """FC workflow output format: [func(param=val)] is AST-parseable.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + # This is the format our FC workflow produces + model_output = "[calculate_triangle_area(base=10, height=5)]" + + item = _make_eval_item(entry, answer, model_output) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 1.0 + + def test_ast_workflow_format_parseable(self): + """AST workflow output: raw text like func(param=val) is parseable.""" + from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single + + entry = _make_simple_entry() + answer = _make_simple_answer() + model_output = "calculate_triangle_area(base=10, height=5)" + + item = _make_eval_item(entry, answer, model_output) + result = _evaluate_single(item, "simple", "Python") + + assert result.score == 1.0 diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py new file mode 100644 index 0000000000..6acb80ade1 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py @@ -0,0 +1,202 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Integration tests for BFCL benchmark pipeline. + +Requires NVIDIA_API_KEY and bfcl package with data files. +Run with: pytest --run_integration --run_slow +""" + +import json +import os +import subprocess + +import pytest + +_SKIP_REASON = None + +try: + from bfcl.constant import PROMPT_PATH, POSSIBLE_ANSWER_PATH + _SIMPLE_FILE = os.path.join(PROMPT_PATH, "BFCL_v3_simple.json") + if not os.path.isfile(_SIMPLE_FILE): + _SKIP_REASON = "BFCL_v3_simple.json not found" +except ImportError: + _SKIP_REASON = "bfcl not installed" + +if not os.environ.get("NVIDIA_API_KEY"): + _SKIP_REASON = "NVIDIA_API_KEY not set" + +pytestmark = [ + pytest.mark.integration, + pytest.mark.slow, + pytest.mark.timeout(300), + pytest.mark.skipif(_SKIP_REASON is not None, reason=_SKIP_REASON or ""), +] + + +@pytest.fixture +def small_bfcl_dataset(tmp_path): + """Create a 5-entry subset of BFCL_v3_simple for fast testing.""" + with open(_SIMPLE_FILE, encoding="utf-8") as f: + entries = [json.loads(line) for line in f if line.strip()][:5] + + test_file = tmp_path / "BFCL_v3_simple.json" + answer_dir = tmp_path / "possible_answer" + answer_dir.mkdir() + answer_file = answer_dir / "BFCL_v3_simple.json" + + with open(test_file, "w") as f: + for e in entries: + f.write(json.dumps(e) + "\n") + + # Copy matching answers + answer_path = os.path.join(POSSIBLE_ANSWER_PATH, "BFCL_v3_simple.json") + if os.path.isfile(answer_path): + entry_ids = {e["id"] for e in entries} + with open(answer_path, encoding="utf-8") as f: + answers = [json.loads(line) for line in f if line.strip()] + with open(answer_file, "w") as f: + for a in answers: + if a["id"] in entry_ids: + f.write(json.dumps(a) + "\n") + + return str(test_file) + + +class TestBFCLIntegration: + + @pytest.mark.asyncio + async def test_end_to_end_bfcl_ast_eval(self, small_bfcl_dataset, tmp_path): + """Full e2e: BFCL AST prompting → LLM → ast_checker → metrics.""" + import yaml + output_dir = str(tmp_path / "output") + + config_dict = { + "llms": { + "nim_llm": { + "_type": "nim", + "model_name": "meta/llama-3.3-70b-instruct", + "api_key": os.environ["NVIDIA_API_KEY"], + "base_url": os.environ.get("NVIDIA_BASE_URL", "https://integrate.api.nvidia.com/v1"), + "max_tokens": 512, + "temperature": 0.0, + }, + }, + "workflow": { + "_type": "bfcl_ast_workflow", + "llm_name": "nim_llm", + }, + "eval": { + "general": { + "output_dir": output_dir, + "workflow_alias": "bfcl_ast_integration_test", + "per_input_user_id": False, + "max_concurrency": 3, + "dataset": { + "_type": "bfcl", + "file_path": small_bfcl_dataset, + "test_category": "simple", + "structure": {"question_key": "question", "answer_key": "answer"}, + }, + }, + "evaluators": { + "bfcl": { + "_type": "bfcl_evaluator", + "test_category": "simple", + "language": "Python", + }, + }, + }, + } + + config_path = tmp_path / "config.yaml" + config_path.write_text(yaml.dump(config_dict, default_flow_style=False)) + + result = subprocess.run( + ["nat", "eval", "--config_file", str(config_path)], + capture_output=True, text=True, timeout=240, + env={**os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"]}, + ) + + assert result.returncode == 0, f"nat eval failed:\n{result.stderr[-2000:]}" + + eval_output = os.path.join(output_dir, "bfcl_output.json") + assert os.path.isfile(eval_output), f"Missing bfcl_output.json in {output_dir}" + + with open(eval_output) as f: + eval_data = json.load(f) + + assert "average_score" in eval_data + assert len(eval_data["eval_output_items"]) == 5 + + # With a 70B model on simple tasks, we expect at least some correct + accuracy = eval_data["average_score"] + assert accuracy > 0, f"Expected accuracy > 0 on simple tasks, got {accuracy}" + + @pytest.mark.asyncio + async def test_end_to_end_bfcl_react_eval(self, small_bfcl_dataset, tmp_path): + """Full e2e: BFCL ReAct workflow → bind_tools loop → intent capture → ast_checker.""" + import yaml + output_dir = str(tmp_path / "react_output") + + config_dict = { + "llms": { + "nim_llm": { + "_type": "nim", + "model_name": "meta/llama-3.3-70b-instruct", + "api_key": os.environ["NVIDIA_API_KEY"], + "base_url": os.environ.get("NVIDIA_BASE_URL", "https://integrate.api.nvidia.com/v1"), + "max_tokens": 512, + "temperature": 0.0, + }, + }, + "workflow": { + "_type": "bfcl_react_workflow", + "llm_name": "nim_llm", + "max_steps": 3, + }, + "eval": { + "general": { + "output_dir": output_dir, + "workflow_alias": "bfcl_react_integration_test", + "per_input_user_id": False, + "max_concurrency": 3, + "dataset": { + "_type": "bfcl", + "file_path": small_bfcl_dataset, + "test_category": "simple", + "structure": {"question_key": "question", "answer_key": "answer"}, + }, + }, + "evaluators": { + "bfcl": { + "_type": "bfcl_evaluator", + "test_category": "simple", + "language": "Python", + }, + }, + }, + } + + config_path = tmp_path / "react_config.yaml" + config_path.write_text(yaml.dump(config_dict, default_flow_style=False)) + + result = subprocess.run( + ["nat", "eval", "--config_file", str(config_path)], + capture_output=True, text=True, timeout=240, + env={**os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"]}, + ) + + assert result.returncode == 0, f"nat eval failed:\n{result.stderr[-2000:]}" + + eval_output = os.path.join(output_dir, "bfcl_output.json") + assert os.path.isfile(eval_output), f"Missing bfcl_output.json in {output_dir}" + + with open(eval_output) as f: + eval_data = json.load(f) + + assert "average_score" in eval_data + assert len(eval_data["eval_output_items"]) == 5 + + # ReAct should also get at least some correct on simple tasks + accuracy = eval_data["average_score"] + assert accuracy > 0, f"Expected accuracy > 0 on simple ReAct tasks, got {accuracy}" diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py new file mode 100644 index 0000000000..0ef7266853 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Regression tests for BFCL evaluator — pinned behavior for known outputs.""" + +import pytest + +from nat.plugins.benchmarks.bfcl.evaluator import _extract_function_call + + +class TestExtractFunctionCall: + + def test_bare_function_call(self): + assert _extract_function_call("calc(x=10)") == "calc(x=10)" + + def test_bracketed_function_call(self): + assert _extract_function_call("[calc(x=10)]") == "[calc(x=10)]" + + def test_markdown_code_block(self): + raw = """Here is the function call: + +```python +calculate_area(base=10, height=5) +```""" + assert _extract_function_call(raw) == "calculate_area(base=10, height=5)" + + def test_markdown_tool_code_block(self): + raw = """```tool_code +func(a=1, b=2) +```""" + assert _extract_function_call(raw) == "func(a=1, b=2)" + + def test_prose_with_function_call_line(self): + raw = """The function to call is: +calculate_area(base=10, height=5) +This will compute the area.""" + assert _extract_function_call(raw) == "calculate_area(base=10, height=5)" + + def test_tools_prefix_stripped(self): + raw = "tools.calculate_area(base=10, height=5)" + result = _extract_function_call(raw) + assert "calculate_area(base=10, height=5)" in result + + def test_multiple_calls_extracted(self): + raw = """func_a(x=1) +func_b(y=2)""" + result = _extract_function_call(raw) + assert "func_a(x=1)" in result + assert "func_b(y=2)" in result + + def test_no_function_call_returns_raw(self): + raw = "I cannot help with that request." + assert _extract_function_call(raw) == raw diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py new file mode 100644 index 0000000000..a2a7f3b83f --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py @@ -0,0 +1,245 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Unit tests for ToolIntentBuffer and tool intent stubs. + +Mirrors the test_tool_intent_buffer.py pattern from react_benchmark_agent, +adapted for our copy at nat.plugins.benchmarks.bfcl.tool_intent_stubs. +""" + +import pytest + +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import ( + ToolIntentBuffer, + PermissiveToolInput, + _GLOBAL_INTENT_REGISTRY, + _current_scenario_id, + _generate_mock_response, + clear_global_intents, + create_tool_stub_function, + get_current_scenario_id, + get_global_intents, + set_current_scenario_id, +) + + +@pytest.fixture(autouse=True) +def clean_global_registry(): + """Clean global registry and reset contextvar before and after each test.""" + _GLOBAL_INTENT_REGISTRY.clear() + _current_scenario_id.set("current") + yield + _GLOBAL_INTENT_REGISTRY.clear() + _current_scenario_id.set("current") + + +class TestToolIntentBuffer: + + def test_init_empty(self): + buf = ToolIntentBuffer() + assert buf.get_intents() == [] + + def test_record_single(self): + buf = ToolIntentBuffer() + buf.record("get_balance", {"account_id": "123"}) + intents = buf.get_intents() + assert len(intents) == 1 + assert intents[0] == {"tool": "get_balance", "parameters": {"account_id": "123"}} + + def test_record_multiple(self): + buf = ToolIntentBuffer() + buf.record("tool_a", {"p": "1"}) + buf.record("tool_b", {"p": "2"}) + buf.record("tool_c", {"p": "3"}) + assert len(buf.get_intents()) == 3 + assert [i["tool"] for i in buf.get_intents()] == ["tool_a", "tool_b", "tool_c"] + + def test_get_intents_returns_copy(self): + buf = ToolIntentBuffer() + buf.record("tool_a", {}) + copy = buf.get_intents() + copy.append({"tool": "fake", "parameters": {}}) + assert len(buf.get_intents()) == 1 + + def test_clear(self): + buf = ToolIntentBuffer() + buf.record("tool_a", {}) + buf.record("tool_b", {}) + buf.clear() + assert buf.get_intents() == [] + + +class TestScenarioIdContextVar: + + def test_default_is_current(self): + assert get_current_scenario_id() == "current" + + def test_set_and_get(self): + set_current_scenario_id("test_123") + assert get_current_scenario_id() == "test_123" + + def test_returns_token(self): + token = set_current_scenario_id("test") + assert token is not None + + def test_initializes_registry(self): + sid = "new_scenario" + set_current_scenario_id(sid) + assert sid in _GLOBAL_INTENT_REGISTRY + assert _GLOBAL_INTENT_REGISTRY[sid] == [] + + +class TestGlobalRegistryIntegration: + + def test_record_stores_globally(self): + sid = "scenario_abc" + set_current_scenario_id(sid) + buf = ToolIntentBuffer() + buf.record("test_tool", {"key": "val"}) + assert len(_GLOBAL_INTENT_REGISTRY[sid]) == 1 + assert _GLOBAL_INTENT_REGISTRY[sid][0]["tool"] == "test_tool" + + def test_clear_clears_global(self): + sid = "scenario_xyz" + set_current_scenario_id(sid) + buf = ToolIntentBuffer() + buf.record("t1", {}) + buf.record("t2", {}) + assert len(_GLOBAL_INTENT_REGISTRY[sid]) == 2 + buf.clear() + assert _GLOBAL_INTENT_REGISTRY[sid] == [] + + def test_record_and_clear_aligned(self): + sid = "aligned" + set_current_scenario_id(sid) + buf = ToolIntentBuffer() + buf.record("t1", {"p": "a"}) + buf.record("t2", {"p": "b"}) + assert len(get_global_intents(sid)) == 2 + buf.clear() + assert get_global_intents(sid) == [] + + def test_multiple_scenarios_isolated(self): + set_current_scenario_id("a") + buf_a = ToolIntentBuffer() + buf_a.record("tool_a", {}) + + set_current_scenario_id("b") + buf_b = ToolIntentBuffer() + buf_b.record("tool_b1", {}) + buf_b.record("tool_b2", {}) + + assert len(get_global_intents("a")) == 1 + assert len(get_global_intents("b")) == 2 + + buf_b.clear() + assert len(get_global_intents("a")) == 1 + assert len(get_global_intents("b")) == 0 + + +class TestGlobalIntentFunctions: + + def test_get_returns_copy(self): + sid = "copy_test" + set_current_scenario_id(sid) + buf = ToolIntentBuffer() + buf.record("tool", {}) + copy = get_global_intents(sid) + copy.append({"tool": "fake", "parameters": {}}) + assert len(get_global_intents(sid)) == 1 + + def test_get_missing_scenario(self): + assert get_global_intents("nonexistent") == [] + + def test_clear_global(self): + sid = "clear_test" + set_current_scenario_id(sid) + buf = ToolIntentBuffer() + buf.record("tool", {}) + clear_global_intents(sid) + assert get_global_intents(sid) == [] + + def test_clear_nonexistent_no_error(self): + clear_global_intents("does_not_exist") + + +class TestPermissiveToolInput: + + def test_dict_passthrough(self): + m = PermissiveToolInput(input_params={"key": "value"}) + assert m.input_params == {"key": "value"} + + def test_json_string_parsed(self): + m = PermissiveToolInput(input_params='{"key": "value"}') + assert m.input_params == {"key": "value"} + + def test_single_quote_json(self): + m = PermissiveToolInput(input_params="{'key': 'value'}") + assert m.input_params == {"key": "value"} + + def test_invalid_string_returns_empty(self): + m = PermissiveToolInput(input_params="not json") + assert m.input_params == {} + + +class TestCreateToolStubFunction: + + @pytest.mark.asyncio + async def test_stub_records_intent(self): + buf = ToolIntentBuffer() + schema = {"title": "test_tool", "description": "A test tool"} + stub_fn, _, desc = create_tool_stub_function(schema, buf, canned_response="OK") + + result = await stub_fn({"param": "val"}) + + assert len(buf.get_intents()) == 1 + assert buf.get_intents()[0]["tool"] == "test_tool" + assert buf.get_intents()[0]["parameters"] == {"param": "val"} + assert result == "OK" + + @pytest.mark.asyncio + async def test_stub_filters_none(self): + buf = ToolIntentBuffer() + schema = {"title": "test_tool", "description": ""} + stub_fn, _, _ = create_tool_stub_function(schema, buf) + + await stub_fn({"valid": "v", "none_param": None}) + + params = buf.get_intents()[0]["parameters"] + assert "none_param" not in params + assert params == {"valid": "v"} + + @pytest.mark.asyncio + async def test_stub_handles_nested_params(self): + buf = ToolIntentBuffer() + schema = {"title": "test_tool", "description": ""} + stub_fn, _, _ = create_tool_stub_function(schema, buf) + + await stub_fn({"params": {"actual": "value"}}) + + assert buf.get_intents()[0]["parameters"] == {"actual": "value"} + + +class TestMockResponseGeneration: + + def test_string(self): + assert _generate_mock_response({"properties": {"n": {"type": "string"}}})["n"] == "mock_n" + + def test_integer(self): + assert _generate_mock_response({"properties": {"c": {"type": "integer"}}})["c"] == 100 + + def test_number(self): + assert _generate_mock_response({"properties": {"a": {"type": "number"}}})["a"] == 100.50 + + def test_boolean(self): + assert _generate_mock_response({"properties": {"b": {"type": "boolean"}}})["b"] is True + + def test_array(self): + assert _generate_mock_response({"properties": {"l": {"type": "array"}}})["l"] == [] + + def test_object(self): + assert _generate_mock_response({"properties": {"d": {"type": "object"}}})["d"] == {} + + def test_multiple_fields(self): + schema = {"properties": {"n": {"type": "string"}, "v": {"type": "integer"}, "b": {"type": "boolean"}}} + result = _generate_mock_response(schema) + assert set(result.keys()) == {"n", "v", "b"} diff --git a/packages/nvidia_nat_benchmarks/tests/byob/__init__.py b/packages/nvidia_nat_benchmarks/tests/byob/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nvidia_nat_benchmarks/tests/byob/conftest.py b/packages/nvidia_nat_benchmarks/tests/byob/conftest.py new file mode 100644 index 0000000000..d51c4fe1e0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/byob/conftest.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py b/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py new file mode 100644 index 0000000000..deec31ac30 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py @@ -0,0 +1,32 @@ +# A minimal BYOB benchmark for testing. +# Uses exact_match scorer with a tiny inline JSONL dataset. + +from nemo_evaluator.contrib.byob import ScorerInput, benchmark, scorer +from nemo_evaluator.contrib.byob.scorers import exact_match + +import json +import os +import tempfile + +# Create a tiny test dataset as a temp file +_DATA = [ + {"id": "0", "question": "What is 2+2?", "target": "4"}, + {"id": "1", "question": "What color is the sky?", "target": "blue"}, + {"id": "2", "question": "Capital of France?", "target": "Paris"}, +] + +_DATASET_PATH = os.path.join(tempfile.gettempdir(), "byob_test_dataset.jsonl") +with open(_DATASET_PATH, "w") as f: + for row in _DATA: + f.write(json.dumps(row) + "\n") + + +@benchmark( + name="test-exact-match", + dataset=_DATASET_PATH, + prompt="{question}", + target_field="target", +) +@scorer +def test_exact_match_scorer(sample: ScorerInput) -> dict: + return exact_match(sample) diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py new file mode 100644 index 0000000000..7f4e235f20 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py @@ -0,0 +1,133 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for the BYOB evaluator — no LLM required.""" + +import json +import os +import sys + +import pytest + +try: + from nemo_evaluator.contrib.byob.decorators import ScorerInput + from nemo_evaluator.contrib.byob.scorers import exact_match, contains, f1_token + _HAS_BYOB = True +except ImportError: + _HAS_BYOB = False + +pytestmark = pytest.mark.skipif(not _HAS_BYOB, reason="nemo_evaluator BYOB not installed") + + +from nat.data_models.evaluator import EvalInputItem + + +class TestBYOBEvaluator: + + def test_exact_match_correct(self): + """Exact match scorer: correct answer scores 1.0.""" + from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + item = EvalInputItem( + id="0", input_obj='{"question": "2+2?"}', + expected_output_obj="4", output_obj="4", + full_dataset_entry={"question": "2+2?", "target": "4"}, + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + + assert result.score == 1.0 + assert result.reasoning["correct"] is True + + def test_exact_match_wrong(self): + """Wrong answer scores 0.0.""" + from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + item = EvalInputItem( + id="1", input_obj='{"question": "2+2?"}', + expected_output_obj="4", output_obj="5", + full_dataset_entry={"question": "2+2?", "target": "4"}, + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + + assert result.score == 0.0 + assert result.reasoning["correct"] is False + + def test_contains_scorer(self): + """Contains scorer: target substring in response.""" + from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + item = EvalInputItem( + id="2", input_obj='{}', + expected_output_obj="Paris", output_obj="The capital of France is Paris.", + full_dataset_entry={"target": "Paris"}, + ) + result = _evaluate_single(item, contains, "target", "correct", {}) + + assert result.score == 1.0 + + def test_f1_token_scorer(self): + """F1 token scorer returns float score.""" + from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + item = EvalInputItem( + id="3", input_obj='{}', + expected_output_obj="the quick brown fox", + output_obj="the quick brown dog", + full_dataset_entry={"target": "the quick brown fox"}, + ) + result = _evaluate_single(item, f1_token, "target", "f1", {}) + + assert 0.0 < result.score < 1.0 # Partial match + assert "f1" in result.reasoning + + def test_none_output_scores_0(self): + """Null output scores 0.0.""" + from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + item = EvalInputItem( + id="4", input_obj='{}', + expected_output_obj="answer", output_obj=None, + full_dataset_entry={}, + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + + assert result.score == 0.0 + + +class TestBYOBBenchmarkImport: + + def test_import_sample_benchmark(self): + """Can import and use the sample benchmark definition.""" + from nemo_evaluator.contrib.byob.eval_logic import import_benchmark + + fixture_path = os.path.join( + os.path.dirname(__file__), "fixtures", "sample_benchmark.py" + ) + bench = import_benchmark(fixture_path, "test_exact_match") + + assert bench.name == "test-exact-match" + assert bench.target_field == "target" + assert bench.scorer_fn is not None + + # Test the scorer + scorer_input = ScorerInput( + response="4", target="4", metadata={}, + ) + result = bench.scorer_fn(scorer_input) + assert result["correct"] is True + + def test_import_and_load_dataset(self): + """Can load dataset from sample benchmark.""" + from nat.plugins.benchmarks.byob.dataset import load_byob_dataset + + fixture_path = os.path.join( + os.path.dirname(__file__), "fixtures", "sample_benchmark.py" + ) + df = load_byob_dataset( + file_path="ignored", + benchmark_module=fixture_path, + benchmark_name="test_exact_match", + ) + + assert len(df) == 3 + assert set(df.columns) >= {"id", "question", "answer"} + assert df.iloc[0]["answer"] == "4" diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py b/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py new file mode 100644 index 0000000000..5d8c57b1c1 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py @@ -0,0 +1,114 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Integration tests for the BYOB evaluator pipeline. + +Tests the evaluator directly (no nat eval subprocess needed) using a minimal +BYOB benchmark definition with pre-constructed eval items. +No LLM or network access required — this validates the BYOB scoring pipeline. +""" + +import json +import os + +import pytest + +try: + from nemo_evaluator.contrib.byob.decorators import ScorerInput + from nemo_evaluator.contrib.byob.eval_logic import import_benchmark + _HAS_BYOB = True +except ImportError: + _HAS_BYOB = False + +pytestmark = pytest.mark.skipif(not _HAS_BYOB, reason="nemo_evaluator BYOB not installed") + +from nat.data_models.evaluator import EvalInput, EvalInputItem +from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + +class TestBYOBIntegration: + + def test_byob_scorer_pipeline_exact_match(self): + """Full pipeline: import benchmark → create items → score with exact_match.""" + fixture_path = os.path.join( + os.path.dirname(__file__), "fixtures", "sample_benchmark.py" + ) + bench = import_benchmark(fixture_path, "test_exact_match") + + # Simulate items that the eval runner would create + items = [ + EvalInputItem( + id="0", + input_obj=json.dumps({"question": "What is 2+2?", "target": "4"}), + expected_output_obj="4", + output_obj="4", # Correct answer + full_dataset_entry={"question": "What is 2+2?", "target": "4"}, + ), + EvalInputItem( + id="1", + input_obj=json.dumps({"question": "Sky color?", "target": "blue"}), + expected_output_obj="blue", + output_obj="red", # Wrong answer + full_dataset_entry={"question": "Sky color?", "target": "blue"}, + ), + EvalInputItem( + id="2", + input_obj=json.dumps({"question": "Capital of France?", "target": "Paris"}), + expected_output_obj="Paris", + output_obj="Paris", # Correct answer + full_dataset_entry={"question": "Capital of France?", "target": "Paris"}, + ), + ] + + results = [] + for item in items: + result = _evaluate_single( + item, bench.scorer_fn, bench.target_field, + "correct", bench.extra_config, + ) + results.append(result) + + # 2 correct, 1 wrong → scores [1.0, 0.0, 1.0] + assert results[0].score == 1.0 + assert results[1].score == 0.0 + assert results[2].score == 1.0 + + avg = sum(r.score for r in results) / len(results) + assert abs(avg - 2 / 3) < 0.01 + + def test_byob_dataset_to_evaluator_roundtrip(self): + """Full roundtrip: load dataset → create items → score.""" + from nat.plugins.benchmarks.byob.dataset import load_byob_dataset + + fixture_path = os.path.join( + os.path.dirname(__file__), "fixtures", "sample_benchmark.py" + ) + + # Load dataset + df = load_byob_dataset("ignored", benchmark_module=fixture_path, benchmark_name="test_exact_match") + assert len(df) == 3 + + # Import benchmark for scorer + bench = import_benchmark(fixture_path, "test_exact_match") + + # Create eval items from DataFrame (simulating what DatasetHandler does) + items = [] + for _, row in df.iterrows(): + items.append(EvalInputItem( + id=row["id"], + input_obj=row["question"], + expected_output_obj=row["answer"], + output_obj=row["answer"], # Simulate perfect answers + full_dataset_entry=json.loads(row["question"]), + )) + + # Score all items + results = [] + for item in items: + result = _evaluate_single( + item, bench.scorer_fn, bench.target_field, + "correct", bench.extra_config, + ) + results.append(result) + + # All should be correct (output == expected) + assert all(r.score == 1.0 for r in results) diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py new file mode 100644 index 0000000000..674ca6de6a --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Conftest for ToolTalk tests. + +ToolTalk's utils.py unconditionally imports torch and transformers for +semantic string comparison (HFVectorizer), but these are never used during +evaluation. We mock them out so tests can run without installing PyTorch. +""" + +import sys +import types +from unittest.mock import MagicMock + + +def _ensure_mock_module(name: str): + """Add a mock module to sys.modules if not already importable.""" + if name not in sys.modules: + try: + __import__(name) + except (ImportError, ModuleNotFoundError): + sys.modules[name] = MagicMock() + + +# Mock torch and transformers before any tooltalk imports trigger them +_ensure_mock_module("torch") +_ensure_mock_module("transformers") diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py new file mode 100644 index 0000000000..7c9373d015 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py @@ -0,0 +1,118 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for the ToolTalk dataset loader — no LLM required.""" + +import json +import os +import tempfile + +import pandas as pd +import pytest + +from nat.plugins.benchmarks.tooltalk.dataset import load_tooltalk_dataset + + +def _make_conversation(conversation_id: str, user_text: str = "Hello") -> dict: + """Create a minimal ToolTalk conversation for testing.""" + return { + "name": f"test-{conversation_id}", + "conversation_id": conversation_id, + "suites_used": ["Alarm"], + "apis_used": ["AddAlarm"], + "scenario": "test scenario", + "user": {"username": "testuser", "session_token": "abc-123"}, + "metadata": { + "location": "New York", + "timestamp": "2023-09-11 13:00:00", + "session_token": "abc-123", + "username": "testuser", + }, + "conversation": [ + {"index": 0, "role": "user", "text": user_text}, + { + "index": 1, + "role": "assistant", + "text": "Done.", + "apis": [{ + "request": {"api_name": "AddAlarm", "parameters": {"time": "18:30:00"}}, + "response": {"alarm_id": "1234-5678"}, + "exception": None, + }], + }, + ], + } + + +class TestLoadToolTalkDataset: + + def test_loads_directory_of_json_files(self, tmp_path): + """Each JSON file in the directory becomes one DataFrame row.""" + for i in range(3): + conv = _make_conversation(f"conv-{i}", f"Message {i}") + (tmp_path / f"conv-{i}.json").write_text(json.dumps(conv)) + + df = load_tooltalk_dataset(str(tmp_path)) + + assert isinstance(df, pd.DataFrame) + assert len(df) == 3 + assert set(df.columns) >= {"id", "question", "answer"} + + def test_question_column_contains_full_conversation_json(self, tmp_path): + """The question column should be the serialized full conversation.""" + conv = _make_conversation("conv-0") + (tmp_path / "conv-0.json").write_text(json.dumps(conv)) + + df = load_tooltalk_dataset(str(tmp_path)) + loaded = json.loads(df.iloc[0]["question"]) + + assert loaded["conversation_id"] == "conv-0" + assert loaded["conversation"][0]["role"] == "user" + assert loaded["metadata"]["location"] == "New York" + + def test_id_column_uses_conversation_id(self, tmp_path): + conv = _make_conversation("my-unique-id") + (tmp_path / "test.json").write_text(json.dumps(conv)) + + df = load_tooltalk_dataset(str(tmp_path)) + assert df.iloc[0]["id"] == "my-unique-id" + + def test_id_falls_back_to_filename_stem(self, tmp_path): + """If conversation_id is missing, use the filename stem.""" + conv = _make_conversation("ignored") + del conv["conversation_id"] + (tmp_path / "fallback-name.json").write_text(json.dumps(conv)) + + df = load_tooltalk_dataset(str(tmp_path)) + assert df.iloc[0]["id"] == "fallback-name" + + def test_raises_on_file_path_not_directory(self, tmp_path): + file_path = tmp_path / "not-a-dir.json" + file_path.write_text("{}") + + with pytest.raises(ValueError, match="must be a directory"): + load_tooltalk_dataset(str(file_path)) + + def test_raises_on_empty_directory(self, tmp_path): + with pytest.raises(ValueError, match="No JSON files found"): + load_tooltalk_dataset(str(tmp_path)) + + def test_loads_real_tooltalk_easy_data(self): + """Smoke test against the installed tooltalk package's easy split.""" + try: + import tooltalk + tooltalk_dir = os.path.dirname(tooltalk.__file__) + easy_dir = os.path.join(tooltalk_dir, "data", "easy") + if not os.path.isdir(easy_dir): + pytest.skip("tooltalk easy data directory not found") + except ImportError: + pytest.skip("tooltalk not installed") + + df = load_tooltalk_dataset(easy_dir) + assert len(df) > 0 + assert "id" in df.columns + + # Verify each row is valid JSON + for _, row in df.iterrows(): + conv = json.loads(row["question"]) + assert "conversation" in conv + assert "metadata" in conv diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py new file mode 100644 index 0000000000..b12085fc65 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py @@ -0,0 +1,157 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Tests for the ToolTalk evaluator — no LLM required. + +These tests construct conversations with predictions already in place +(simulating what the workflow would produce) and verify that the evaluator +correctly computes ToolTalk metrics. +""" + +import json +import os + +import pytest + +from nat.data_models.evaluator import EvalInputItem +from nat.plugins.benchmarks.tooltalk.evaluator import _evaluate_single + + +def _get_database_dir(): + """Get the path to ToolTalk's database directory.""" + try: + import tooltalk + db_dir = os.path.join(os.path.dirname(tooltalk.__file__), "data", "databases") + if os.path.isdir(db_dir): + return db_dir + except ImportError: + pass + return None + + +@pytest.fixture +def database_dir(): + db_dir = _get_database_dir() + if db_dir is None: + pytest.skip("tooltalk not installed or database directory not found") + return db_dir + + +def _make_conversation_with_predictions(predictions_match_ground_truth: bool) -> dict: + """Create a ToolTalk conversation with predictions already attached. + + If predictions_match_ground_truth is True, the predictions exactly match + the ground truth API calls (success case). + """ + correct_api_call = { + "request": { + "api_name": "AddAlarm", + "parameters": {"session_token": "98a5a87a-7714-b404", "time": "18:30:00"}, + }, + "response": {"alarm_id": "5bff-dd80"}, + "exception": None, + } + + wrong_api_call = { + "request": { + "api_name": "AddAlarm", + "parameters": {"session_token": "98a5a87a-7714-b404", "time": "19:00:00"}, + }, + "response": {"alarm_id": "aaaa-bbbb"}, + "exception": None, + } + + prediction_api = correct_api_call.copy() if predictions_match_ground_truth else wrong_api_call.copy() + prediction_api["role"] = "api" + prediction_api["match"] = False # Will be set by evaluate_predictions + prediction_api["bad_action"] = False + + return { + "name": "test-conversation", + "conversation_id": "test-001", + "suites_used": ["Alarm"], + "apis_used": ["AddAlarm"], + "scenario": "test", + "user": { + "username": "justinkool", + "email": "test@test.com", + "phone": "123-456-7890", + "name": "Justin Kool", + "password": "testpass123", + "session_token": "98a5a87a-7714-b404", + }, + "metadata": { + "location": "New York", + "timestamp": "2023-09-11 13:00:00", + "session_token": "98a5a87a-7714-b404", + "username": "justinkool", + }, + "conversation": [ + {"index": 0, "role": "user", "text": "Set an alarm for 6:30 PM"}, + { + "index": 1, + "role": "assistant", + "text": "Alarm set.", + "apis": [correct_api_call], + "predictions": [ + prediction_api, + {"role": "assistant", "text": "Alarm set."}, + ], + }, + ], + } + + +class TestToolTalkEvaluator: + + def test_perfect_predictions_score_1(self, database_dir): + """When predictions exactly match ground truth, success score should be 1.0.""" + conv = _make_conversation_with_predictions(predictions_match_ground_truth=True) + + item = EvalInputItem( + id="test-001", + input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), + full_dataset_entry=conv, + ) + + result = _evaluate_single(item, database_dir) + + assert result.id == "test-001" + assert result.score == 1.0 + assert result.reasoning["success"] == 1.0 + assert result.reasoning["recall"] == 1.0 + assert result.reasoning["bad_action_rate"] == 0.0 + + def test_wrong_predictions_score_0(self, database_dir): + """When predictions don't match ground truth, success should be 0.""" + conv = _make_conversation_with_predictions(predictions_match_ground_truth=False) + + item = EvalInputItem( + id="test-002", + input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), + full_dataset_entry=conv, + ) + + result = _evaluate_single(item, database_dir) + + assert result.id == "test-002" + assert result.score == 0.0 + assert result.reasoning["recall"] == 0.0 + + def test_none_output_returns_zero_score(self, database_dir): + """If output_obj is None (workflow failed), score should be 0.""" + item = EvalInputItem( + id="test-003", + input_obj="{}", + expected_output_obj="{}", + output_obj=None, + full_dataset_entry={}, + ) + + result = _evaluate_single(item, database_dir) + + assert result.score == 0.0 + assert "error" in result.reasoning diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py new file mode 100644 index 0000000000..87be98211f --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py @@ -0,0 +1,165 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Integration tests for the ToolTalk benchmark pipeline. + +These tests call a live NIM endpoint and exercise the full +dataset → workflow → evaluator path. They require: + - NVIDIA_API_KEY environment variable + - tooltalk package installed + - Network access to the NIM API + +Run with: pytest -m integration packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py +""" + +import json +import os +import shutil +import tempfile + +import pytest + +_SKIP_REASON = None + +try: + import tooltalk + _TOOLTALK_DIR = os.path.dirname(tooltalk.__file__) + _DATABASE_DIR = os.path.join(_TOOLTALK_DIR, "data", "databases") + _EASY_DIR = os.path.join(_TOOLTALK_DIR, "data", "easy") + if not os.path.isdir(_DATABASE_DIR): + _SKIP_REASON = "tooltalk database directory not found" +except ImportError: + _SKIP_REASON = "tooltalk not installed" + +if not os.environ.get("NVIDIA_API_KEY"): + _SKIP_REASON = "NVIDIA_API_KEY not set" + +pytestmark = [ + pytest.mark.integration, + pytest.mark.slow, + pytest.mark.timeout(300), + pytest.mark.skipif(_SKIP_REASON is not None, reason=_SKIP_REASON or ""), +] + + +@pytest.fixture +def single_conversation_dir(tmp_path): + """Create a temp directory with a single AddAlarm-easy conversation.""" + src = os.path.join(_EASY_DIR, "AddAlarm-easy.json") + if not os.path.isfile(src): + pytest.skip("AddAlarm-easy.json not found in tooltalk data") + shutil.copy2(src, tmp_path) + return str(tmp_path) + + +class TestToolTalkIntegration: + + @pytest.mark.asyncio + async def test_workflow_produces_predictions(self, single_conversation_dir): + """The workflow calls a live NIM endpoint and produces tool call predictions.""" + from nat.plugins.benchmarks.tooltalk.dataset import load_tooltalk_dataset + from nat.plugins.benchmarks.tooltalk.workflow import _build_tool_schemas, _build_messages + + # Load dataset + df = load_tooltalk_dataset(single_conversation_dir) + assert len(df) == 1 + + conv = json.loads(df.iloc[0]["question"]) + assert "conversation" in conv + assert conv["apis_used"] == ["AddAlarm"] + + @pytest.mark.asyncio + async def test_end_to_end_nat_eval(self, single_conversation_dir, tmp_path): + """Full end-to-end: nat eval config → workflow → evaluator → metrics output.""" + output_dir = str(tmp_path / "output") + + # Build a config dict programmatically (avoids YAML env var issues) + config_dict = { + "llms": { + "nim_llm": { + "_type": "nim", + "model_name": "meta/llama-3.3-70b-instruct", + "api_key": os.environ["NVIDIA_API_KEY"], + "base_url": os.environ.get( + "NVIDIA_BASE_URL", "https://integrate.api.nvidia.com/v1" + ), + "max_tokens": 1024, + "temperature": 0.0, + }, + }, + "workflow": { + "_type": "tooltalk_workflow", + "llm_name": "nim_llm", + "database_dir": _DATABASE_DIR, + "api_mode": "all", + "max_tool_calls_per_turn": 3, + }, + "eval": { + "general": { + "output_dir": output_dir, + "workflow_alias": "tooltalk_integration_test", + "per_input_user_id": True, + "max_concurrency": 1, + "dataset": { + "_type": "tooltalk", + "file_path": single_conversation_dir, + "database_dir": _DATABASE_DIR, + "structure": { + "question_key": "question", + "answer_key": "answer", + }, + }, + }, + "evaluators": { + "tooltalk": { + "_type": "tooltalk_evaluator", + "database_dir": _DATABASE_DIR, + }, + }, + }, + } + + # Write config to a temp YAML + import yaml + config_path = tmp_path / "test_config.yaml" + config_path.write_text(yaml.dump(config_dict, default_flow_style=False)) + + # Run eval via subprocess (same as `nat eval --config_file ...`) + import subprocess + result = subprocess.run( + ["nat", "eval", "--config_file", str(config_path)], + capture_output=True, + text=True, + timeout=240, + env={**os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"]}, + ) + + # Check that the eval completed + assert result.returncode == 0, f"nat eval failed:\nstdout: {result.stdout}\nstderr: {result.stderr}" + + # Verify output files exist + workflow_output = os.path.join(output_dir, "workflow_output.json") + eval_output = os.path.join(output_dir, "tooltalk_output.json") + assert os.path.isfile(workflow_output), f"Missing workflow_output.json in {output_dir}" + assert os.path.isfile(eval_output), f"Missing tooltalk_output.json in {output_dir}" + + # Verify eval output structure + with open(eval_output) as f: + eval_data = json.load(f) + assert "average_score" in eval_data + assert "eval_output_items" in eval_data + assert len(eval_data["eval_output_items"]) == 1 + + item = eval_data["eval_output_items"][0] + assert "score" in item + assert "reasoning" in item + + # The reasoning should have ToolTalk metrics + reasoning = item["reasoning"] + assert "recall" in reasoning + assert "bad_action_rate" in reasoning + assert "success" in reasoning + + # recall should be > 0 (the LLM should at least call AddAlarm once correctly) + assert reasoning["recall"] > 0, ( + f"Expected recall > 0 (LLM should call AddAlarm correctly), got {reasoning}" + ) diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py new file mode 100644 index 0000000000..3eb09ee6cf --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py @@ -0,0 +1,196 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Regression tests for ToolTalk evaluator scoring logic. + +These tests use pre-constructed conversations with specific prediction patterns +to verify that the evaluator produces deterministic, expected metric values. +No LLM or network access required. +""" + +import json +import os + +import pytest + +from nat.data_models.evaluator import EvalInputItem +from nat.plugins.benchmarks.tooltalk.evaluator import _evaluate_single + + +def _get_database_dir(): + try: + import tooltalk + db_dir = os.path.join(os.path.dirname(tooltalk.__file__), "data", "databases") + return db_dir if os.path.isdir(db_dir) else None + except ImportError: + return None + + +@pytest.fixture +def database_dir(): + db_dir = _get_database_dir() + if db_dir is None: + pytest.skip("tooltalk not installed or database directory not found") + return db_dir + + +def _make_alarm_conversation(predictions: list[dict]) -> dict: + """Build a ToolTalk AddAlarm conversation with given predictions.""" + return { + "name": "regression-test", + "conversation_id": "regression-001", + "suites_used": ["Alarm"], + "apis_used": ["AddAlarm"], + "scenario": "regression", + "user": { + "username": "justinkool", + "email": "test@test.com", + "phone": "123-456-7890", + "name": "Justin Kool", + "password": "testpass123", + "session_token": "98a5a87a-7714-b404", + }, + "metadata": { + "location": "New York", + "timestamp": "2023-09-11 13:00:00", + "session_token": "98a5a87a-7714-b404", + "username": "justinkool", + }, + "conversation": [ + {"index": 0, "role": "user", "text": "Set an alarm for 6:30 PM"}, + { + "index": 1, + "role": "assistant", + "text": "Alarm set.", + "apis": [{ + "request": {"api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "18:30:00", + }}, + "response": {"alarm_id": "5bff-dd80"}, + "exception": None, + }], + "predictions": predictions, + }, + ], + } + + +class TestToolTalkEvaluatorRegression: + """Regression tests: pinned metric values for known prediction patterns.""" + + def test_single_correct_prediction_is_success(self, database_dir): + """1 correct prediction matching 1 ground truth = success.""" + predictions = [ + { + "role": "api", + "request": {"api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "18:30:00", + }}, + "response": {"alarm_id": "5bff-dd80"}, + "exception": None, + }, + {"role": "assistant", "text": "Alarm set."}, + ] + conv = _make_alarm_conversation(predictions) + item = EvalInputItem( + id="reg-001", input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), full_dataset_entry=conv, + ) + result = _evaluate_single(item, database_dir) + + # Pinned expected values + assert result.score == 1.0 + assert result.reasoning["recall"] == 1.0 + assert result.reasoning["matches"] == 1 + assert result.reasoning["predictions"] == 1 + assert result.reasoning["bad_actions"] == 0 + assert result.reasoning["bad_action_rate"] == 0.0 + assert result.reasoning["success"] == 1.0 + + def test_correct_plus_extra_calls_has_bad_actions(self, database_dir): + """1 correct + 2 extra same calls = recall 1.0 but bad_action_rate > 0, success 0.""" + predictions = [ + { + "role": "api", + "request": {"api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "18:30:00", + }}, + "response": {"alarm_id": "5bff-dd80"}, + "exception": None, + }, + { + "role": "api", + "request": {"api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "18:30:00", + }}, + "response": {"alarm_id": "aaaa-bbbb"}, + "exception": None, + }, + { + "role": "api", + "request": {"api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "18:30:00", + }}, + "response": {"alarm_id": "cccc-dddd"}, + "exception": None, + }, + {"role": "assistant", "text": "Alarm set."}, + ] + conv = _make_alarm_conversation(predictions) + item = EvalInputItem( + id="reg-002", input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), full_dataset_entry=conv, + ) + result = _evaluate_single(item, database_dir) + + assert result.reasoning["recall"] == 1.0 + assert result.reasoning["matches"] == 1 + assert result.reasoning["predictions"] == 3 + assert result.reasoning["actions"] == 3 + assert result.reasoning["bad_actions"] == 2 + assert result.reasoning["success"] == 0.0 + assert result.score == 0.0 + + def test_wrong_api_call_zero_recall(self, database_dir): + """Calling the wrong API = recall 0, success 0.""" + predictions = [ + { + "role": "api", + "request": {"api_name": "DeleteAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", "alarm_id": "5bff-dd80", + }}, + "response": None, + "exception": "Alarm not found", + }, + {"role": "assistant", "text": "Done."}, + ] + conv = _make_alarm_conversation(predictions) + item = EvalInputItem( + id="reg-003", input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), full_dataset_entry=conv, + ) + result = _evaluate_single(item, database_dir) + + assert result.reasoning["recall"] == 0.0 + assert result.reasoning["matches"] == 0 + assert result.score == 0.0 + + def test_no_predictions_zero_recall(self, database_dir): + """No API predictions at all = recall 0.""" + predictions = [ + {"role": "assistant", "text": "I can't do that."}, + ] + conv = _make_alarm_conversation(predictions) + item = EvalInputItem( + id="reg-004", input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), full_dataset_entry=conv, + ) + result = _evaluate_single(item, database_dir) + + assert result.reasoning["recall"] == 0.0 + assert result.reasoning["predictions"] == 0 + assert result.reasoning["bad_action_rate"] == 0.0 + assert result.score == 0.0 diff --git a/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py b/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py new file mode 100644 index 0000000000..80729a3b39 --- /dev/null +++ b/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py @@ -0,0 +1,273 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Validates Open Question #2 from NAT_NATIVE_DESIGN.md: + + "Can @register_per_user_function_group provide per-item stub isolation + in the eval context?" + +The eval runner generates a unique user_id per item when per_input_user_id=True +(the default). This causes SessionManager.session(user_id=unique_id) to create +a fresh PerUserWorkflowBuilder per item, which in turn creates fresh +@register_per_user_function_group instances with clean state. + +This test validates that mechanism directly using the SessionManager API — the +same path the eval runner takes — without requiring a live LLM endpoint. + +Architecture note: +- Per-user function groups are ONLY instantiated when the workflow is also + registered as per-user (@register_per_user_function). When the workflow is + per-user, SessionManager creates a PerUserWorkflowBuilder for each unique + user_id, and that builder instantiates all per-user function groups fresh. +- The echo workflow here is therefore registered with @register_per_user_function + to match the real eval-runner pattern. + +Expected outcome: +- Each unique user_id gets a fresh function group instance (counter starts at 0) +- State accumulated in one user's session does NOT bleed into another user's session +- This proves per-item isolation is available out-of-the-box for benchmarks that + use @register_per_user_function_group. +""" + +import asyncio +from uuid import uuid4 + +import pytest +from pydantic import BaseModel, Field + +from nat.builder.builder import Builder +from nat.builder.function import FunctionGroup +from nat.builder.function_info import FunctionInfo +from nat.builder.workflow_builder import WorkflowBuilder +from nat.cli.register_workflow import register_per_user_function_group, register_per_user_function +from nat.data_models.config import Config, GeneralConfig +from nat.data_models.function import FunctionGroupBaseConfig, FunctionBaseConfig +from nat.runtime.session import SessionManager + + +# --------------------------------------------------------------------------- +# Schemas +# --------------------------------------------------------------------------- + +class IncrementInput(BaseModel): + n: int = Field(default=1, description="Amount to add to the counter") + + +class CounterOutput(BaseModel): + count: int = Field(description="Counter value after operation") + instance_id: str = Field(description="Unique ID of this function group instance") + + +class EchoInput(BaseModel): + text: str + + +# --------------------------------------------------------------------------- +# Config types (unique names to avoid conflicts with other tests) +# --------------------------------------------------------------------------- + +class IsolationCounterGroupConfig(FunctionGroupBaseConfig, name="isolation_counter_group"): + """Per-user function group with a counter — validates fresh-instance-per-user.""" + initial_value: int = Field(default=0) + + +class EchoWorkflowConfig(FunctionBaseConfig, name="isolation_echo_workflow"): + """ + Minimal per-user echo workflow. + + Must be registered with @register_per_user_function so that SessionManager + sets _is_workflow_per_user=True. Only then does it create a + PerUserWorkflowBuilder per unique user_id, which in turn instantiates each + @register_per_user_function_group fresh for that user. + """ + pass + + +# --------------------------------------------------------------------------- +# Component registrations +# --------------------------------------------------------------------------- + +@pytest.fixture(scope="module", autouse=True) +def _register_components(): + """Register test components once for the module.""" + + @register_per_user_function_group(config_type=IsolationCounterGroupConfig) + async def isolation_counter_group(config: IsolationCounterGroupConfig, builder: Builder): + """ + Per-user function group. Each user_id gets its own isolated counter + and a unique instance_id so we can detect which instance responded. + """ + # State is local to this generator invocation — fresh per user_id + counter = {"value": config.initial_value} + instance_id = str(uuid4()) + + group = FunctionGroup(config=config) + + async def increment(inp: IncrementInput) -> CounterOutput: + counter["value"] += inp.n + return CounterOutput(count=counter["value"], instance_id=instance_id) + + async def get_count(inp: IncrementInput) -> CounterOutput: + return CounterOutput(count=counter["value"], instance_id=instance_id) + + group.add_function(name="increment", fn=increment, input_schema=IncrementInput, + description="Increment counter by n") + group.add_function(name="get_count", fn=get_count, input_schema=IncrementInput, + description="Get current count without incrementing") + + yield group + + # The workflow must be per-user so that SessionManager creates a + # PerUserWorkflowBuilder per unique user_id (which instantiates per-user + # function groups fresh for each user). + @register_per_user_function(config_type=EchoWorkflowConfig, + input_type=EchoInput, + single_output_type=str) + async def echo_workflow(config: EchoWorkflowConfig, builder: Builder): + async def _echo(inp: EchoInput) -> str: + return inp.text + + yield FunctionInfo.from_fn(_echo) + + +# --------------------------------------------------------------------------- +# Helper: build a minimal Config using the per-user function group +# --------------------------------------------------------------------------- + +def _make_config() -> Config: + return Config( + general=GeneralConfig(), + workflow=EchoWorkflowConfig(), + function_groups={"counter": IsolationCounterGroupConfig()}, + ) + + +# --------------------------------------------------------------------------- +# Tests +# --------------------------------------------------------------------------- + +class TestPerUserFunctionGroupEvalIsolation: + """ + Validates that @register_per_user_function_group provides fresh instances + per user_id — matching what the eval runner does with per_input_user_id=True. + """ + + @pytest.mark.asyncio + async def test_different_user_ids_get_independent_counters(self): + """ + Two sessions with different user_ids must have independent counter state. + This mirrors what the eval runner does: user_id = base_id + "-" + uuid4() + for each eval item when per_input_user_id=True (the default). + """ + config = _make_config() + + async with WorkflowBuilder.from_config(config) as shared_builder: + session_manager = await SessionManager.create(config=config, shared_builder=shared_builder) + + user_id_a = f"eval-item-{uuid4()}" + user_id_b = f"eval-item-{uuid4()}" + + # User A increments their counter twice + async with session_manager.session(user_id=user_id_a) as session_a: + fns_a = await session_a.workflow.function_groups["counter"].get_accessible_functions() + increment_a = fns_a["counter__increment"] + await increment_a.ainvoke(IncrementInput(n=1)) + result_a1 = await increment_a.ainvoke(IncrementInput(n=1)) + + # User B increments their counter once + async with session_manager.session(user_id=user_id_b) as session_b: + fns_b = await session_b.workflow.function_groups["counter"].get_accessible_functions() + increment_b = fns_b["counter__increment"] + result_b1 = await increment_b.ainvoke(IncrementInput(n=1)) + + await session_manager.shutdown() + + # A's counter should be 2, B's should be 1 — isolated + assert result_a1.count == 2, f"User A counter expected 2, got {result_a1.count}" + assert result_b1.count == 1, f"User B counter expected 1, got {result_b1.count}" + + # Instance IDs must be different — they are separate objects + assert result_a1.instance_id != result_b1.instance_id, ( + "Different user_ids must produce different function group instances" + ) + + @pytest.mark.asyncio + async def test_same_user_id_shares_state(self): + """ + Two calls within the same user_id session share state. + Confirms that the per-user isolation is at the user_id boundary, + not per-call. + """ + config = _make_config() + + async with WorkflowBuilder.from_config(config) as shared_builder: + session_manager = await SessionManager.create(config=config, shared_builder=shared_builder) + + user_id = f"eval-item-{uuid4()}" + + async with session_manager.session(user_id=user_id) as session: + fns = await session.workflow.function_groups["counter"].get_accessible_functions() + increment = fns["counter__increment"] + get_count = fns["counter__get_count"] + + await increment.ainvoke(IncrementInput(n=5)) + result = await get_count.ainvoke(IncrementInput(n=0)) + + await session_manager.shutdown() + + # Within the same session, state accumulates + assert result.count == 5, f"Expected count 5, got {result.count}" + + @pytest.mark.asyncio + async def test_eval_runner_pattern_unique_user_ids_give_fresh_instances(self): + """ + Simulates exactly what the eval runner does with per_input_user_id=True + (the default, per EvalGeneralConfig line 124-128): + + user_id = config.user_id + "-" + str(uuid4()) # per eval item + + Each item gets user_id += f"-{uuid4()}" — so N items -> N unique user_ids + -> N fresh function group instances. This test runs 3 simulated items + concurrently and verifies complete isolation. + """ + config = _make_config() + base_user_id = "eval-run-001" + + async with WorkflowBuilder.from_config(config) as shared_builder: + session_manager = await SessionManager.create(config=config, shared_builder=shared_builder) + + async def simulate_eval_item(item_index: int) -> dict: + # Mimic: user_id = config.user_id + "-" + str(uuid4()) + user_id = f"{base_user_id}-{uuid4()}" + + async with session_manager.session(user_id=user_id) as session: + fns = await session.workflow.function_groups["counter"].get_accessible_functions() + increment = fns["counter__increment"] + + # Each item increments by item_index+1 times + result = None + for _ in range(item_index + 1): + result = await increment.ainvoke(IncrementInput(n=1)) + + return {"item": item_index, "count": result.count, "instance_id": result.instance_id} + + # Run 3 items concurrently (mimics eval runner's asyncio.gather) + results = await asyncio.gather( + simulate_eval_item(0), # should end up with count=1 + simulate_eval_item(1), # should end up with count=2 + simulate_eval_item(2), # should end up with count=3 + ) + + await session_manager.shutdown() + + # Each item should have its own isolated count + counts = {r["item"]: r["count"] for r in results} + assert counts[0] == 1, f"Item 0 expected count=1, got {counts[0]}" + assert counts[1] == 2, f"Item 1 expected count=2, got {counts[1]}" + assert counts[2] == 3, f"Item 2 expected count=3, got {counts[2]}" + + # All instance_ids must be distinct — 3 separate objects + instance_ids = {r["instance_id"] for r in results} + assert len(instance_ids) == 3, ( + f"Expected 3 distinct function group instances, got {len(instance_ids)}: {instance_ids}" + ) From aa9bb6e72a47b9e9759efa655065dfdeb1c73b62 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sat, 7 Mar 2026 08:36:00 -0800 Subject: [PATCH 02/10] example READMEs and license updates Signed-off-by: Bryan Bednarski --- docs/source/improve-workflows/evaluate.md | 21 +++ .../benchmarks/agent_leaderboard/README.md | 89 +++++++-- .../agent_leaderboard/pyproject.toml | 15 ++ .../__init__.py | 13 ++ .../configs/eval_all_domains.yml | 15 ++ .../configs/eval_banking.yml | 15 ++ .../register.py | 13 ++ examples/benchmarks/bfcl/README.md | 175 ++++++++++++++++-- examples/benchmarks/bfcl/pyproject.toml | 15 ++ .../bfcl/src/nat_benchmark_bfcl/__init__.py | 13 ++ .../configs/eval_ast_simple.yml | 15 ++ .../configs/eval_fc_simple.yml | 16 ++ .../configs/eval_react_simple.yml | 16 ++ .../bfcl/src/nat_benchmark_bfcl/register.py | 13 ++ examples/benchmarks/byob/README.md | 130 +++++++++++-- examples/benchmarks/byob/pyproject.toml | 15 ++ .../byob/src/nat_benchmark_byob/__init__.py | 13 ++ .../configs/eval_exact_match.yml | 15 ++ .../byob/src/nat_benchmark_byob/register.py | 13 ++ examples/benchmarks/tooltalk/README.md | 36 +++- examples/benchmarks/tooltalk/pyproject.toml | 15 ++ .../src/nat_benchmark_tooltalk/__init__.py | 13 ++ .../configs/eval_easy.yml | 15 ++ .../src/nat_benchmark_tooltalk/register.py | 13 ++ .../src/nat/meta/pypi.md | 23 +++ .../src/nat/plugins/benchmarks/__init__.py | 12 ++ .../benchmarks/agent_leaderboard/__init__.py | 12 ++ .../benchmarks/agent_leaderboard/config.py | 12 ++ .../benchmarks/agent_leaderboard/dataset.py | 12 ++ .../benchmarks/agent_leaderboard/evaluator.py | 12 ++ .../benchmarks/agent_leaderboard/workflow.py | 12 ++ .../nat/plugins/benchmarks/bfcl/__init__.py | 12 ++ .../src/nat/plugins/benchmarks/bfcl/config.py | 12 ++ .../nat/plugins/benchmarks/bfcl/dataset.py | 12 ++ .../nat/plugins/benchmarks/bfcl/evaluator.py | 12 ++ .../plugins/benchmarks/bfcl/workflow_ast.py | 12 ++ .../plugins/benchmarks/bfcl/workflow_fc.py | 12 ++ .../plugins/benchmarks/bfcl/workflow_react.py | 12 ++ .../nat/plugins/benchmarks/byob/__init__.py | 12 ++ .../src/nat/plugins/benchmarks/byob/config.py | 12 ++ .../nat/plugins/benchmarks/byob/dataset.py | 12 ++ .../nat/plugins/benchmarks/byob/evaluator.py | 12 ++ .../src/nat/plugins/benchmarks/register.py | 12 ++ .../plugins/benchmarks/tooltalk/__init__.py | 12 ++ .../nat/plugins/benchmarks/tooltalk/config.py | 12 ++ .../plugins/benchmarks/tooltalk/dataset.py | 12 ++ .../plugins/benchmarks/tooltalk/evaluator.py | 12 ++ .../plugins/benchmarks/tooltalk/workflow.py | 12 ++ .../nvidia_nat_benchmarks/tests/__init__.py | 14 ++ .../tests/agent_leaderboard/__init__.py | 14 ++ .../tests/agent_leaderboard/conftest.py | 12 ++ .../tests/agent_leaderboard/test_dataset.py | 12 ++ .../tests/agent_leaderboard/test_evaluator.py | 12 ++ .../tests/bfcl/__init__.py | 14 ++ .../tests/bfcl/conftest.py | 12 ++ .../tests/bfcl/test_dataset.py | 12 ++ .../tests/bfcl/test_evaluator.py | 12 ++ .../tests/bfcl/test_integration.py | 12 ++ .../tests/bfcl/test_regression.py | 12 ++ .../tests/bfcl/test_tool_intent_stubs.py | 12 ++ .../tests/byob/__init__.py | 14 ++ .../tests/byob/conftest.py | 12 ++ .../tests/byob/fixtures/sample_benchmark.py | 16 +- .../tests/byob/test_evaluator.py | 12 ++ .../tests/byob/test_integration.py | 12 ++ .../tests/tooltalk/__init__.py | 14 ++ .../tests/tooltalk/conftest.py | 12 ++ .../tests/tooltalk/test_dataset.py | 12 ++ .../tests/tooltalk/test_evaluator.py | 12 ++ .../tests/tooltalk/test_integration.py | 12 ++ .../tests/tooltalk/test_regression.py | 12 ++ .../src/nat/data_models/evaluate_config.py | 9 + .../eval/dataset_handler/dataset_handler.py | 12 +- .../src/nat/plugins/eval/runtime/evaluate.py | 4 +- 74 files changed, 1277 insertions(+), 59 deletions(-) create mode 100644 packages/nvidia_nat_benchmarks/src/nat/meta/pypi.md diff --git a/docs/source/improve-workflows/evaluate.md b/docs/source/improve-workflows/evaluate.md index 37d3743f2b..e4969042d1 100644 --- a/docs/source/improve-workflows/evaluate.md +++ b/docs/source/improve-workflows/evaluate.md @@ -1021,6 +1021,27 @@ eval: max_concurrency: 4 ``` +### Shuffling evaluation order + +By default, evaluation items are processed in the order they appear in the dataset. To randomize the order, enable `shuffle` in the `eval.general` section. This can help reduce ordering bias in evaluation results — for example, when using KV cache or prefix sharing optimizations that may favor items processed together. + +```yaml +eval: + general: + shuffle: true +``` + +For reproducible shuffling across runs, set `shuffle_seed` to a fixed integer: + +```yaml +eval: + general: + shuffle: true + shuffle_seed: 42 +``` + +When `shuffle_seed` is omitted, a different random order is used each run. + ### Pickup where you left off When running the evaluation on a large dataset, it is recommended to resume the evaluation from where it was left off. This is particularly useful while using overloaded services that may timeout while running the workflow. When that happens a workflow interrupted warning is issued and workflow output is saved to a file. diff --git a/examples/benchmarks/agent_leaderboard/README.md b/examples/benchmarks/agent_leaderboard/README.md index 59d4696105..0c0cdf6a0b 100644 --- a/examples/benchmarks/agent_leaderboard/README.md +++ b/examples/benchmarks/agent_leaderboard/README.md @@ -1,5 +1,19 @@ - - + # Galileo Agent Leaderboard v2 Evaluation @@ -119,6 +133,44 @@ nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_bankin ## Understanding Results +### The `agent_leaderboard_tsq` evaluator + +This example uses the **Tool Selection Quality (TSQ)** evaluator (`_type: agent_leaderboard_tsq` in the eval config). It compares the tool calls the agent made (captured by the workflow via `ToolIntentBuffer`) against the expected tool calls derived from the scenario's user goals. + +The evaluator computes an **F1 score** between predicted and expected tool sets: +- **Precision** = (correctly predicted tools) / (total predicted tools) +- **Recall** = (correctly predicted tools) / (total expected tools) +- **F1** = 2 × precision × recall / (precision + recall) + +Tool names are normalized before comparison (case-insensitive, underscores/hyphens stripped, module prefixes removed) so that `banking_tools__get_account_balance` matches `get_account_balance`. + +The evaluator is configured in the YAML under `eval.evaluators`: + +```yaml +evaluators: + tsq: + _type: agent_leaderboard_tsq + tool_weight: 1.0 # Weight for tool selection F1 (default: 1.0) + parameter_weight: 0.0 # Weight for parameter accuracy (default: 0.0) +``` + +The final score per item is `tool_weight × tool_f1 + parameter_weight × param_accuracy`. With default weights, only tool selection matters. + +### Per-item metrics + +Each item in the evaluator output contains: + +| Field | Description | +|-------|-------------| +| `tool_selection_f1` | F1 score between predicted and expected tool names | +| `parameter_accuracy` | Parameter correctness (placeholder — future enhancement) | +| `predicted_tools` | Normalized list of tools the agent called | +| `expected_tools` | Normalized list of tools expected from user goals | +| `num_predicted` | Total tool call intents captured | +| `num_expected` | Total expected tool calls from ground truth | + +### Inspect results + ```bash python -c " import json @@ -137,25 +189,25 @@ for item in data['eval_output_items'][:3]: **Example output:** ``` -Average TSQ F1: 0.425 -Total scenarios: 100 +Average TSQ F1: 0.650 +Total scenarios: 10 banking_scenario_000: + F1=1.00 predicted=['getaccountbalance'] + expected=['getaccountbalance'] + banking_scenario_001: F1=0.67 predicted=['getaccountbalance', 'gettransactionhistory'] expected=['getaccountbalance', 'transferfunds'] - banking_scenario_001: - F1=1.00 predicted=['getloaninformation'] - expected=['getloaninformation'] banking_scenario_002: F1=0.00 predicted=['scheduleappointment'] expected=['getexchangerates'] ``` -### TSQ Score interpretation +### Score interpretation -| Score | Meaning | -|-------|---------| +| F1 Score | Meaning | +|----------|---------| | 1.0 | All expected tools predicted, no extra tools | -| 0.5-0.9 | Partial match — some tools correct, some missing or extra | +| 0.5–0.9 | Partial match — some tools correct, some missing or extra | | 0.0 | No overlap between predicted and expected tools | --- @@ -179,10 +231,11 @@ nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_all_do ### Available domains -| Domain | Description | Typical tool count | -|--------|-------------|-------------------| -| `banking` | Account management, transfers, loans | ~20 tools | -| `healthcare` | Appointments, prescriptions, records | ~15 tools | -| `insurance` | Policies, claims, coverage | ~15 tools | -| `investment` | Portfolio, stocks, trading | ~15 tools | -| `telecom` | Plans, billing, support | ~15 tools | +| Domain | Scenarios | Tools | Personas | Description | +|--------|-----------|-------|----------|-------------| +| `banking` | 100 | 20 | 100 | Account management, transfers, loans, cards | +| `healthcare` | 100 | 20 | 100 | Appointments, prescriptions, medical records | +| `insurance` | 100 | 20 | 100 | Policies, claims, coverage, renewals | +| `investment` | 100 | 20 | 100 | Portfolio management, stocks, trading | +| `telecom` | 100 | 20 | 100 | Plans, billing, support, device management | +| **Total** | **500** | **100** | **500** | | diff --git a/examples/benchmarks/agent_leaderboard/pyproject.toml b/examples/benchmarks/agent_leaderboard/pyproject.toml index 7a6241a84c..c14fc18c38 100644 --- a/examples/benchmarks/agent_leaderboard/pyproject.toml +++ b/examples/benchmarks/agent_leaderboard/pyproject.toml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + [build-system] build-backend = "setuptools.build_meta" requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py index fb0bad0357..0ac2afc2c1 100644 --- a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py @@ -1,3 +1,16 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + from . import register # noqa: F401 diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml index 58688c6cb6..04a47036fa 100644 --- a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_all_domains.yml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Agent Leaderboard v2 — All domains evaluation # Usage: nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_all_domains.yml diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml index 2339b2f1ef..2f0ed5ca5f 100644 --- a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/configs/eval_banking.yml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Agent Leaderboard v2 — Banking domain evaluation # Usage: nat eval --config_file examples/benchmarks/agent_leaderboard/configs/eval_banking.yml diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py index c278e4e89a..62316d4594 100644 --- a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py +++ b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py @@ -1,4 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Components are registered via nvidia-nat-benchmarks package entry points. # This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/bfcl/README.md b/examples/benchmarks/bfcl/README.md index 1f4261d460..71c61b9b3d 100644 --- a/examples/benchmarks/bfcl/README.md +++ b/examples/benchmarks/bfcl/README.md @@ -1,5 +1,19 @@ - - + # BFCL Benchmark Evaluation @@ -45,20 +59,84 @@ pip install nvidia-bfcl ## Set Up Environment +### 1. Set your NVIDIA API key + ```bash export NVIDIA_API_KEY= +``` + +Or add it to a `.env` file in your project root (NAT loads `.env` automatically). + +### 2. Locate the BFCL dataset + +The `nvidia-bfcl` package ships with all BFCL v3 datasets and ground-truth answers as JSONL files. Each line is one test entry containing a user question and one or more function schemas. The ground-truth answers (in `possible_answer/`) contain the expected function call(s) with parameter values. + +**Dataset structure:** + +``` +bfcl/data/ +├── BFCL_v3_simple.json # 400 single function call test entries +├── BFCL_v3_multiple.json # 200 select-one-of-many function entries +├── BFCL_v3_parallel.json # 200 multiple calls in one response +├── BFCL_v3_parallel_multiple.json # 200 combined parallel + multiple +├── BFCL_v3_java.json # 100 Java function call syntax +├── BFCL_v3_javascript.json # 50 JavaScript function call syntax +├── BFCL_v3_irrelevance.json # 240 model should refuse (no valid tool) +├── BFCL_v3_live_simple.json # 258 live/real-world simple calls +├── BFCL_v3_live_multiple.json # 1053 live multiple function entries +├── BFCL_v3_sql.json # 100 SQL function calls +└── possible_answer/ + ├── BFCL_v3_simple.json # Ground-truth answers for simple + ├── BFCL_v3_multiple.json # Ground-truth answers for multiple + └── ... # (not all categories have answers) +``` + +Each test entry looks like: + +```json +{ + "id": "simple_0", + "question": [[{"role": "user", "content": "Find the area of a triangle with base 10 and height 5."}]], + "function": [{"name": "calculate_triangle_area", "description": "...", "parameters": {...}}] +} +``` + +The matching ground-truth answer: + +```json +{ + "id": "simple_0", + "ground_truth": [{"calculate_triangle_area": {"base": [10], "height": [5], "unit": ["units", ""]}}] +} +``` -# Locate the BFCL dataset file +**Locate the installed dataset path:** + +```bash python -c " -from bfcl.constant import PROMPT_PATH -print(f'export BFCL_DATASET_FILE={PROMPT_PATH}/BFCL_v3_simple.json') +from bfcl.constant import PROMPT_PATH, POSSIBLE_ANSWER_PATH +print(f'Dataset dir: {PROMPT_PATH}') +print(f'Answers dir: {POSSIBLE_ANSWER_PATH}') " ``` +**Expected output:** +``` +Dataset dir: /path/to/.venv/lib/python3.11/site-packages/bfcl/data +Answers dir: /path/to/.venv/lib/python3.11/site-packages/bfcl/data/possible_answer +``` + +### 3. Set the dataset path + +Point `BFCL_DATASET_FILE` to the specific test category you want to evaluate: + ```bash -export BFCL_DATASET_FILE= +# Simple (400 entries) — recommended starting point +export BFCL_DATASET_FILE=/path/to/.venv/lib/python3.11/site-packages/bfcl/data/BFCL_v3_simple.json ``` +> The evaluator automatically resolves the matching `possible_answer/` file from the same directory. If no answer file exists for a category, entries score 0 (the evaluator needs ground truth to compare against). + --- ## Evaluation Mode 1: AST Prompting @@ -97,7 +175,24 @@ Uses `llm.bind_tools(schemas)` — the LLM makes structured tool calls via the n nat eval --config_file examples/benchmarks/bfcl/configs/eval_fc_simple.yml ``` -This mode typically achieves higher accuracy than AST prompting because the LLM uses its native function calling capability rather than generating text. +**Expected output:** +``` +INFO - Starting evaluation run with config file: .../eval_fc_simple.yml +INFO - Loaded 400 possible answers from .../possible_answer/BFCL_v3_simple.json +INFO - Loaded 400 BFCL entries from BFCL_v3_simple.json (category: simple) +Running workflow: 100%|██████████| 400/400 [05:30<00:00, 1.21s/it] +INFO - BFCL evaluation complete: accuracy=0.720 (288/400) category=simple + +=== EVALUATION SUMMARY === +| Evaluator | Avg Score | Output File | +|-----------|-------------|------------------| +| bfcl | 0.720 | bfcl_output.json | +``` + +> FC mode converts BFCL's function schemas to OpenAI tool format and uses `bind_tools()`. +> The LLM returns structured `tool_calls` with typed arguments, but accuracy can be lower +> than AST prompting when the schema type conversion (BFCL types → OpenAPI types) loses +> precision or the model returns string values where integers are expected. --- @@ -109,12 +204,51 @@ Drives a multi-step reasoning loop: the LLM reasons about which tool to call, ex nat eval --config_file examples/benchmarks/bfcl/configs/eval_react_simple.yml ``` -This mode demonstrates NAT-native agent execution against BFCL — the agent can reason step-by-step before making tool calls. +**Expected output:** +``` +INFO - Starting evaluation run with config file: .../eval_react_simple.yml +INFO - Loaded 400 possible answers from .../possible_answer/BFCL_v3_simple.json +INFO - Loaded 400 BFCL entries from BFCL_v3_simple.json (category: simple) +Running workflow: 100%|██████████| 400/400 [12:00<00:00, 1.80s/it] +INFO - BFCL evaluation complete: accuracy=0.900 (360/400) category=simple + +=== EVALUATION SUMMARY === +| Evaluator | Avg Score | Output File | +|-----------|-------------|------------------| +| bfcl | 0.900 | bfcl_output.json | +``` + +> ReAct mode uses `bind_tools()` like FC mode but adds a multi-step reasoning loop with +> canned tool responses. It also applies type coercion (string → int/float based on the BFCL +> schema) and deduplication of repeated tool calls, which typically produces the highest +> accuracy of the three modes. The tradeoff is higher latency due to multiple LLM calls per item. --- ## Understanding Results +### The `bfcl_evaluator` + +All three evaluation modes use the same evaluator: **`bfcl_evaluator`** (`_type: bfcl_evaluator` in the eval config). It calls BFCL's `ast_checker()` function directly in Python to validate the model's function call output against the ground-truth possible answers. The evaluator handles three steps: + +1. **Extract** the function call from the model's raw output (strips markdown, prose, JSON wrapping) +2. **Decode** the extracted text into a structured function call via BFCL's `default_decode_ast_prompting()` +3. **Check** the decoded call against ground truth via `ast_checker()` — validates function name, parameter names, types, and values + +The evaluator is configured in the YAML under `eval.evaluators`: + +```yaml +evaluators: + bfcl: + _type: bfcl_evaluator + test_category: simple # Must match the dataset's test category + language: Python # Python, Java, or JavaScript +``` + +Each item scores **1.0** (all checks pass) or **0.0** (any mismatch). The `average_score` is the accuracy across all items. + +### Output files + Results are saved to `.tmp/nat/benchmarks/bfcl/_simple/`: ```bash @@ -157,15 +291,22 @@ Accuracy: 0.850 Change the `test_category` and `file_path` in the config to evaluate different BFCL splits: -| Category | File | Description | -|----------|------|-------------| -| `simple` | `BFCL_v3_simple.json` | Single function call | -| `multiple` | `BFCL_v3_multiple.json` | Select one of multiple candidate functions | -| `parallel` | `BFCL_v3_parallel.json` | Multiple function calls in one response | -| `parallel_multiple` | `BFCL_v3_parallel_multiple.json` | Combined parallel + multiple | -| `java` | `BFCL_v3_java.json` | Java function call syntax | -| `javascript` | `BFCL_v3_javascript.json` | JavaScript function call syntax | -| `irrelevance` | `BFCL_v3_irrelevance.json` | Model should refuse (no valid tool) | +| Category | File | Samples | Has Answers | Description | +|----------|------|---------|-------------|-------------| +| `simple` | `BFCL_v3_simple.json` | 400 | Yes | Single function call | +| `multiple` | `BFCL_v3_multiple.json` | 200 | Yes | Select one of multiple candidate functions | +| `parallel` | `BFCL_v3_parallel.json` | 200 | Yes | Multiple function calls in one response | +| `parallel_multiple` | `BFCL_v3_parallel_multiple.json` | 200 | Yes | Combined parallel + multiple | +| `java` | `BFCL_v3_java.json` | 100 | Yes | Java function call syntax | +| `javascript` | `BFCL_v3_javascript.json` | 50 | Yes | JavaScript function call syntax | +| `irrelevance` | `BFCL_v3_irrelevance.json` | 240 | No | Model should refuse (no valid tool) | +| `live_simple` | `BFCL_v3_live_simple.json` | 258 | Yes | Real-world simple function calls | +| `live_multiple` | `BFCL_v3_live_multiple.json` | 1,053 | Yes | Real-world multiple function calls | +| `sql` | `BFCL_v3_sql.json` | 100 | Yes | SQL function calls | + +> Categories without answers (`Has Answers: No`) can still run the workflow, but the evaluator +> cannot score them — all entries will score 0. The `irrelevance` category is the exception: +> the evaluator checks that the model does *not* produce a function call (no answer file needed). For Java/JavaScript categories, set `language` in the evaluator config: diff --git a/examples/benchmarks/bfcl/pyproject.toml b/examples/benchmarks/bfcl/pyproject.toml index dc36db96ff..b14fb3bd71 100644 --- a/examples/benchmarks/bfcl/pyproject.toml +++ b/examples/benchmarks/bfcl/pyproject.toml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + [build-system] build-backend = "setuptools.build_meta" requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py index fb0bad0357..0ac2afc2c1 100644 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py @@ -1,3 +1,16 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + from . import register # noqa: F401 diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml index 45b30c2b35..c60f4a29e7 100644 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_ast_simple.yml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # BFCL v3 — AST Prompting on simple split # Usage: nat eval --config_file examples/benchmarks/bfcl/configs/eval_ast_simple.yml diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml index 687ef6b2b2..3701ec91a5 100644 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_fc_simple.yml @@ -1,3 +1,19 @@ + +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # BFCL v3 — Native Function Calling on simple split # Usage: nat eval --config_file examples/benchmarks/bfcl/configs/eval_fc_simple.yml diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml index 1554ec2851..5325054643 100644 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/configs/eval_react_simple.yml @@ -1,3 +1,19 @@ + +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # BFCL v3 — ReAct (tool-calling loop with intent capture) on simple split # Usage: nat eval --config_file examples/benchmarks/bfcl/configs/eval_react_simple.yml diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py index c278e4e89a..62316d4594 100644 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py +++ b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py @@ -1,4 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Components are registered via nvidia-nat-benchmarks package entry points. # This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/byob/README.md b/examples/benchmarks/byob/README.md index 3891bdf451..8a436a9770 100644 --- a/examples/benchmarks/byob/README.md +++ b/examples/benchmarks/byob/README.md @@ -1,19 +1,58 @@ - - + # BYOB (Bring Your Own Benchmark) Evaluation -**Complexity:** 🟢 Beginner +**Complexity:** 🟡 Intermediate + +Run [NeMo Evaluator BYOB](https://docs.nvidia.com/nemo/evaluator/) benchmarks directly on NAT agent workflows — without re-implementing the dataset loader or scorer logic. + +## Why BYOB in NAT? -Score NAT agent workflow outputs using [NeMo Evaluator's BYOB framework](https://docs.nvidia.com/nemo/evaluator/). BYOB lets you define custom benchmarks with any dataset and scorer — this example shows how to plug BYOB scorers into NAT's evaluation pipeline. +NeMo Evaluator's BYOB (Bring Your Own Benchmark) framework lets users define custom evaluation benchmarks using the `@benchmark` and `@scorer` decorators. A benchmark definition specifies a dataset, a prompt template, and a scorer function — everything needed to evaluate a model. + +Normally, NeMo Evaluator runs the full pipeline: it loads the dataset, renders prompts, calls the model endpoint, and scores the responses. **This integration reuses the benchmark definition, dataset loading, and scorer functions from NeMo Evaluator, but replaces the model-calling step with NAT's workflow execution.** This means: + +- **Existing BYOB benchmarks work as-is** — the same `@benchmark` + `@scorer` Python file you use with NeMo Evaluator works identically with NAT. No re-implementation needed. +- **NAT handles the agent execution** — instead of calling a model endpoint, NAT runs its own workflow (tool-calling agents, RAG pipelines, multi-step reasoning chains) to generate responses. +- **Scorers run in-process** — the scorer receives `ScorerInput(response=workflow_output, target=ground_truth)` and returns a score dict. `model_call_fn` is `None` (NAT handles all LLM calls upstream). + +``` +┌─────────────────────────────────────┐ +│ BYOB Benchmark Definition (.py) │ ← Written once, used in both systems +│ @benchmark + @scorer │ +├───────────────┬─────────────────────┤ +│ NeMo Evaluator│ NAT Integration │ +│ (standalone) │ (this example) │ +│ │ │ +│ load_dataset()│ load_dataset() │ ← Same function, reused +│ render_prompt │ NAT workflow │ ← NAT replaces model calling +│ call_model() │ (agents, tools) │ +│ scorer_fn() │ scorer_fn() │ ← Same scorer, reused +└───────────────┴─────────────────────┘ +``` ## Key Features -- **Any BYOB benchmark**: Use any benchmark defined with `@benchmark` + `@scorer` decorators -- **Built-in scorers**: `exact_match`, `contains`, `f1_token`, `bleu`, `rouge`, `regex_match` +- **Direct reuse**: Any benchmark defined with `@benchmark` + `@scorer` works without modification +- **Built-in scorers**: `exact_match`, `contains`, `f1_token`, `bleu`, `rouge`, `regex_match` — all from `nemo_evaluator.contrib.byob.scorers` - **Custom scorers**: Write your own scorer function with `ScorerInput` -- **No model_call_fn needed**: BYOB scorers run in-process — NAT handles the LLM calls -- **Dataset from benchmark**: Dataset path, prompt template, and target field come from the benchmark definition +- **HuggingFace datasets**: BYOB's `load_dataset()` supports `hf://` URIs, local JSONL, CSV, and TSV +- **Dataset from benchmark**: Dataset path, prompt template, and target field come from the benchmark definition — no duplication in NAT config ## Table of Contents @@ -113,6 +152,27 @@ INFO - BYOB evaluation complete: avg_correct=0.XXX (3 items) ## Understanding Results +### The `byob_evaluator` + +This example uses the **`byob_evaluator`** (`_type: byob_evaluator` in the eval config). It imports the benchmark definition at evaluation time, then calls `bench.scorer_fn(ScorerInput(...))` for each item to produce a score dict. + +The evaluator is configured in the YAML under `eval.evaluators`: + +```yaml +evaluators: + byob: + _type: byob_evaluator + benchmark_module: /path/to/my_benchmark.py # Same file used for the dataset + benchmark_name: my_qa_test # Normalized benchmark name + score_field: correct # Key from scorer output to use as primary score +``` + +The `score_field` parameter controls which key from the scorer's output dict becomes the item's primary score. For `exact_match` and `contains`, this is `correct` (boolean → 1.0 or 0.0). For `f1_token`, you'd set `score_field: f1` to get the F1 float. The `average_score` in the output is the mean of all items' primary scores. + +The metrics available in each item's `reasoning` dict depend entirely on what the scorer function returns — the evaluator passes through the full scorer output without modification. + +### Inspect results + ```bash python -c " import json @@ -137,16 +197,50 @@ Average score: 0.667 ## Built-in Scorers Reference -| Scorer | Score field | Description | -|--------|-----------|-------------| -| `exact_match` | `correct` | Case-insensitive, whitespace-trimmed equality | -| `contains` | `correct` | Target is a substring of response | -| `f1_token` | `f1` | Token-level F1 (also returns `precision`, `recall`) | -| `regex_match` | `correct` | Target is a regex pattern matched against response | -| `bleu` | `bleu_1`..`bleu_4` | BLEU-1 through BLEU-4 with smoothing | -| `rouge` | `rouge_1`, `rouge_2`, `rouge_l` | ROUGE F1 scores | +BYOB scorers come from the [NeMo Evaluator](https://docs.nvidia.com/nemo/evaluator/) framework (`nemo_evaluator.contrib.byob.scorers`). They are standard NLP evaluation metrics packaged as simple Python functions that accept a `ScorerInput` and return a dict of metric values. When you use BYOB through NAT, the scorer runs in-process against the workflow's output — NAT handles the LLM calls and the scorer only sees the final `(response, target)` pair. + +You can use any built-in scorer directly, compose them with `any_of()` / `all_of()`, or write your own from scratch. The only requirement is the signature: `def scorer(sample: ScorerInput) -> dict`. + +### Simple scorers + +These return a single `correct` boolean. Use `score_field: correct` in the evaluator config. + +| Scorer | Import | What it checks | +|--------|--------|----------------| +| `exact_match` | `from nemo_evaluator.contrib.byob.scorers import exact_match` | Case-insensitive, whitespace-trimmed string equality | +| `contains` | `from nemo_evaluator.contrib.byob.scorers import contains` | Whether the target appears as a substring of the response | +| `regex_match` | `from nemo_evaluator.contrib.byob.scorers import regex_match` | Whether the response matches a regex pattern (target is the pattern) | + +### Metric scorers + +These return numeric scores. Set `score_field` to the metric you want as the primary score. + +| Scorer | Import | Returns | +|--------|--------|---------| +| `f1_token` | `from nemo_evaluator.contrib.byob.scorers import f1_token` | `{"f1": float, "precision": float, "recall": float}` — token-level overlap | +| `bleu` | `from nemo_evaluator.contrib.byob.scorers import bleu` | `{"bleu_1": float, ..., "bleu_4": float}` — sentence-level BLEU with smoothing | +| `rouge` | `from nemo_evaluator.contrib.byob.scorers import rouge` | `{"rouge_1": float, "rouge_2": float, "rouge_l": float}` — ROUGE F1 scores | + +### Composer functions + +Combine multiple scorers into one: + +| Function | What it does | +|----------|-------------| +| `any_of(exact_match, contains)` | Correct if **any** scorer passes | +| `all_of(exact_match, regex_match)` | Correct only if **all** scorers pass | + +```python +from nemo_evaluator.contrib.byob.scorers import exact_match, contains, any_of + +@scorer +def flexible_scorer(sample: ScorerInput) -> dict: + return any_of(exact_match, contains)(sample) +``` + +### Configuring `score_field` -Set `score_field` in the evaluator config to match your scorer: +Set `score_field` in the evaluator config to tell NAT which key from the scorer output dict to use as the primary score: ```yaml evaluators: @@ -154,7 +248,7 @@ evaluators: _type: byob_evaluator benchmark_module: /path/to/benchmark.py benchmark_name: my_benchmark - score_field: f1 # For f1_token scorer + score_field: f1 # For f1_token scorer (default: "correct") ``` --- diff --git a/examples/benchmarks/byob/pyproject.toml b/examples/benchmarks/byob/pyproject.toml index 32042dac15..c425044c4d 100644 --- a/examples/benchmarks/byob/pyproject.toml +++ b/examples/benchmarks/byob/pyproject.toml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + [build-system] build-backend = "setuptools.build_meta" requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py b/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py index fb0bad0357..0ac2afc2c1 100644 --- a/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py +++ b/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py @@ -1,3 +1,16 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + from . import register # noqa: F401 diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml b/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml index 7952ff3d6b..f2eadfc495 100644 --- a/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml +++ b/examples/benchmarks/byob/src/nat_benchmark_byob/configs/eval_exact_match.yml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # BYOB — Exact Match benchmark evaluation # Usage: nat eval --config_file examples/benchmarks/byob/configs/eval_exact_match.yml # diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/register.py b/examples/benchmarks/byob/src/nat_benchmark_byob/register.py index c278e4e89a..62316d4594 100644 --- a/examples/benchmarks/byob/src/nat_benchmark_byob/register.py +++ b/examples/benchmarks/byob/src/nat_benchmark_byob/register.py @@ -1,4 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Components are registered via nvidia-nat-benchmarks package entry points. # This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/tooltalk/README.md b/examples/benchmarks/tooltalk/README.md index 4685d25dc9..536efae89f 100644 --- a/examples/benchmarks/tooltalk/README.md +++ b/examples/benchmarks/tooltalk/README.md @@ -1,5 +1,19 @@ - - + # ToolTalk Benchmark Evaluation @@ -124,6 +138,21 @@ nat eval --config_file examples/benchmarks/tooltalk/configs/eval_easy.yml ## Understanding Results +### The `tooltalk_evaluator` + +This example uses the **`tooltalk_evaluator`** (`_type: tooltalk_evaluator` in the eval config). It calls ToolTalk's built-in `ToolExecutor.evaluate_predictions()` directly in Python to compare the agent's predicted API calls against the ground-truth calls in each conversation. For each conversation, it produces the metrics described below. + +The evaluator is configured in the YAML under `eval.evaluators`: + +```yaml +evaluators: + tooltalk: + _type: tooltalk_evaluator + database_dir: ${TOOLTALK_DATABASE_DIR} +``` + +### Output files + Results are saved to `.tmp/nat/benchmarks/tooltalk/easy/`: ```bash @@ -131,6 +160,9 @@ ls .tmp/nat/benchmarks/tooltalk/easy/ # config_original.yml config_effective.yml workflow_output.json tooltalk_output.json ``` +- `workflow_output.json` — raw workflow responses (conversations with predictions) +- `tooltalk_output.json` — evaluator scores and per-conversation metrics + ### Inspect per-conversation metrics ```bash diff --git a/examples/benchmarks/tooltalk/pyproject.toml b/examples/benchmarks/tooltalk/pyproject.toml index 8da87ccfff..6632196f0e 100644 --- a/examples/benchmarks/tooltalk/pyproject.toml +++ b/examples/benchmarks/tooltalk/pyproject.toml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + [build-system] build-backend = "setuptools.build_meta" requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py index fb0bad0357..0ac2afc2c1 100644 --- a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py +++ b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py @@ -1,3 +1,16 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + from . import register # noqa: F401 diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml index 1413e719da..37ff8c8f5d 100644 --- a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml +++ b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/configs/eval_easy.yml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # ToolTalk Easy Split — Multi-turn function calling evaluation # Usage: nat eval --config_file examples/benchmarks/tooltalk/configs/eval_easy.yml diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py index c278e4e89a..62316d4594 100644 --- a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py +++ b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py @@ -1,4 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Components are registered via nvidia-nat-benchmarks package entry points. # This register.py exists for the example package structure convention. diff --git a/packages/nvidia_nat_benchmarks/src/nat/meta/pypi.md b/packages/nvidia_nat_benchmarks/src/nat/meta/pypi.md new file mode 100644 index 0000000000..58ec7535cb --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/meta/pypi.md @@ -0,0 +1,23 @@ + + +![NVIDIA NeMo Agent Toolkit](https://media.githubusercontent.com/media/NVIDIA/NeMo-Agent-Toolkit/refs/heads/main/docs/source/_static/banner.png "NeMo Agent Toolkit banner image") + +# NVIDIA NeMo Agent Toolkit Subpackage +This is a subpackage for [`NeMo Agent Toolkit Benchmarks`], which integrates key agentic workflow evaluations from [NeMo Evaluator](https://github.com/NVIDIA-NeMo/Evaluator/tree/main) and [HuggingFace datasets](https://huggingface.co/datasets) into the Toolkit for rapid benchmark evaluation. + +For more information about the NVIDIA NeMo Agent Toolkit, please visit the [NeMo Agent Toolkit GitHub Repo](https://github.com/NVIDIA/NeMo-Agent-Toolkit). diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/__init__.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/__init__.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py index c09cac23e1..713b6370fc 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Configuration types for Galileo Agent Leaderboard v2 benchmark.""" from collections.abc import Callable diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py index e65ddf109e..1baff64f54 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Agent Leaderboard v2 dataset loader. Downloads from HuggingFace galileo-ai/agent-leaderboard-v2 and transforms diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py index 3383b12b7d..f166b35fd4 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tool Selection Quality (TSQ) evaluator for Agent Leaderboard. Computes F1 score between predicted tool calls (from workflow output) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py index 36671d7007..d0b3066882 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Agent Leaderboard workflow. Drives a tool-calling loop using tool stubs from the dataset. diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/__init__.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py index 0576180b24..b0c9b9ad7c 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Configuration types for the BFCL benchmark.""" from collections.abc import Callable diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py index 9e01704ec2..2b6cf3d06e 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BFCL dataset loader. Loads BFCL v3 JSONL test files into a DataFrame compatible with NAT's eval runner. diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py index 2d3e28776a..5bd1b50ad4 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BFCL benchmark evaluator. Calls BFCL's ast_checker directly in-process to score model outputs. diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py index cf275e3469..a3fef455a0 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BFCL AST (prompting) workflow. Serializes function schemas as text in the system prompt and makes a single diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py index 24ff7e1409..ba43e4bfd3 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BFCL Native FC workflow. Uses llm.bind_tools(schemas) + ainvoke() to make the LLM produce structured diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py index 52a6e1a6a3..928df7d362 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BFCL ReAct workflow. Drives a ReAct-style tool-calling loop using NAT's LLM with bind_tools(). diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/__init__.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py index ad64ecd840..72612aaf05 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Configuration types for BYOB (Bring Your Own Benchmark) integration.""" from collections.abc import Callable diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py index 0151dac255..bbaa43ba86 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BYOB dataset loader. Imports a BYOB benchmark definition and loads its dataset into a DataFrame diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py index be508aa186..941c50b3a0 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """BYOB benchmark evaluator. Calls bench.scorer_fn(ScorerInput(...)) directly in-process. diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py index 5059d73b91..e2a263247b 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/register.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. # flake8: noqa diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/__init__.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py index 3bdbc77bfd..a6227f9dc1 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. from collections.abc import Callable from pathlib import Path diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py index ab2219a143..a02ea7c1df 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. import json import logging diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py index 1ad624f82f..358fbbf467 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """ToolTalk benchmark evaluator. Uses ToolTalk's built-in evaluation logic to compare predicted API calls against diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py index 78a3804678..b3b9e74f36 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """ToolTalk benchmark workflow. Replays multi-turn ToolTalk conversations using NAT's LLM with tool calling. diff --git a/packages/nvidia_nat_benchmarks/tests/__init__.py b/packages/nvidia_nat_benchmarks/tests/__init__.py index e69de29bb2..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/__init__.py +++ b/packages/nvidia_nat_benchmarks/tests/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py index e69de29bb2..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py index 731029f8bc..2d69d1bf66 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for Agent Leaderboard dataset loader — no network required for unit tests.""" import json diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py index 6664190295..681655853a 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for the Agent Leaderboard TSQ evaluator — no LLM required.""" import json diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py b/packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py index e69de29bb2..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py b/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py index 732a3550f1..0ded8198b4 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/conftest.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Conftest for BFCL tests — mocks optional dependencies if missing.""" import sys diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py index 88156fd815..4cfaaf8b74 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for the BFCL dataset loader — no LLM required.""" import json diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py index 80eee68081..62cdab2c63 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for the BFCL evaluator — no LLM required. Uses pre-constructed model outputs to validate that ast_checker scoring works diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py index 6acb80ade1..b97cf44437 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Integration tests for BFCL benchmark pipeline. Requires NVIDIA_API_KEY and bfcl package with data files. diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py index 0ef7266853..f8c31f65f4 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Regression tests for BFCL evaluator — pinned behavior for known outputs.""" import pytest diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py index a2a7f3b83f..59fd9f3c59 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Unit tests for ToolIntentBuffer and tool intent stubs. Mirrors the test_tool_intent_buffer.py pattern from react_benchmark_agent, diff --git a/packages/nvidia_nat_benchmarks/tests/byob/__init__.py b/packages/nvidia_nat_benchmarks/tests/byob/__init__.py index e69de29bb2..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/__init__.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/byob/conftest.py b/packages/nvidia_nat_benchmarks/tests/byob/conftest.py index d51c4fe1e0..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/conftest.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/conftest.py @@ -1,2 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py b/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py index deec31ac30..b9e1b6a5f6 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py @@ -1,5 +1,17 @@ -# A minimal BYOB benchmark for testing. -# Uses exact_match scorer with a tiny inline JSONL dataset. +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. from nemo_evaluator.contrib.byob import ScorerInput, benchmark, scorer from nemo_evaluator.contrib.byob.scorers import exact_match diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py index 7f4e235f20..d8379cd3f7 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for the BYOB evaluator — no LLM required.""" import json diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py b/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py index 5d8c57b1c1..bf04404b16 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Integration tests for the BYOB evaluator pipeline. Tests the evaluator directly (no nat eval subprocess needed) using a minimal diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py index e69de29bb2..bcd923c929 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py index 674ca6de6a..a3ccce69c3 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Conftest for ToolTalk tests. ToolTalk's utils.py unconditionally imports torch and transformers for diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py index 7c9373d015..dfb1306b09 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for the ToolTalk dataset loader — no LLM required.""" import json diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py index b12085fc65..b56c8c9aad 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Tests for the ToolTalk evaluator — no LLM required. These tests construct conversations with predictions already in place diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py index 87be98211f..89e7c9e857 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Integration tests for the ToolTalk benchmark pipeline. These tests call a live NIM endpoint and exercise the full diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py index 3eb09ee6cf..87fb55297a 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py @@ -1,5 +1,17 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +# +# 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. """Regression tests for ToolTalk evaluator scoring logic. These tests use pre-constructed conversations with specific prediction patterns diff --git a/packages/nvidia_nat_core/src/nat/data_models/evaluate_config.py b/packages/nvidia_nat_core/src/nat/data_models/evaluate_config.py index d2785a7134..61a66aa266 100644 --- a/packages/nvidia_nat_core/src/nat/data_models/evaluate_config.py +++ b/packages/nvidia_nat_core/src/nat/data_models/evaluate_config.py @@ -127,6 +127,15 @@ class EvalGeneralConfig(BaseModel): "this creates a fresh workflow instance per eval item, resetting all stateful tools to their " "initial state. Set to False to disable this behavior.") + shuffle: bool = Field( + default=False, + description="When enabled, randomizes the order of evaluation items before running the workflow. " + "Useful for reducing ordering bias in evaluation results.") + + shuffle_seed: int | None = Field( + default=None, + description="Random seed for reproducible shuffling. If None, uses a different random order each run.") + # overwrite the output_dir with the output config if present @model_validator(mode="before") @classmethod diff --git a/packages/nvidia_nat_eval/src/nat/plugins/eval/dataset_handler/dataset_handler.py b/packages/nvidia_nat_eval/src/nat/plugins/eval/dataset_handler/dataset_handler.py index 396463974a..dcb9c718f0 100644 --- a/packages/nvidia_nat_eval/src/nat/plugins/eval/dataset_handler/dataset_handler.py +++ b/packages/nvidia_nat_eval/src/nat/plugins/eval/dataset_handler/dataset_handler.py @@ -43,7 +43,9 @@ def __init__(self, concurrency: int, num_passes: int = 1, adjust_dataset_size: bool = False, - custom_pre_eval_process_function: str | None = None): + custom_pre_eval_process_function: str | None = None, + shuffle: bool = False, + shuffle_seed: int | None = None): from nat.plugins.eval.utils.intermediate_step_adapter import IntermediateStepAdapter self.dataset_config = dataset_config @@ -55,6 +57,10 @@ def __init__(self, self.num_passes = num_passes self.adjust_dataset_size = adjust_dataset_size + # Shuffle configuration + self.shuffle = shuffle + self.shuffle_seed = shuffle_seed + # Custom pre-evaluation process function self.custom_pre_eval_process_function = custom_pre_eval_process_function @@ -221,6 +227,10 @@ def _preprocess_dataframe(self, input_df: pd.DataFrame) -> pd.DataFrame: if (self.dataset_config.id_key in input_df.columns): input_df.drop_duplicates(subset=[self.dataset_config.id_key], inplace=True) + # Shuffle dataset order if requested + if self.shuffle: + input_df = input_df.sample(frac=1, random_state=self.shuffle_seed).reset_index(drop=True) + if self.reps > 1 and self.adjust_dataset_size: raise ValueError("reps and adjust_dataset_size are mutually exclusive") diff --git a/packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/evaluate.py b/packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/evaluate.py index 8256c8b8f5..af352d5a5a 100644 --- a/packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/evaluate.py +++ b/packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/evaluate.py @@ -679,7 +679,9 @@ async def run_and_evaluate(self, concurrency=self.eval_config.general.max_concurrency, num_passes=self.config.num_passes, adjust_dataset_size=self.config.adjust_dataset_size, - custom_pre_eval_process_function=custom_pre_eval_process_function) + custom_pre_eval_process_function=custom_pre_eval_process_function, + shuffle=self.eval_config.general.shuffle, + shuffle_seed=self.eval_config.general.shuffle_seed) self.eval_input = dataset_handler.get_eval_input_from_dataset(self.config.dataset) if self.eval_input.eval_input_items: try: From 2cbc4edeebfe9b9c18b273869491d7d69feb1106 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sat, 7 Mar 2026 09:03:09 -0800 Subject: [PATCH 03/10] evaluator unit tests Signed-off-by: Bryan Bednarski --- .../nat/plugins/benchmarks/bfcl/evaluator.py | 21 +- .../plugins/benchmarks/tooltalk/evaluator.py | 13 +- .../test_evaluator_comprehensive.py | 137 ++++++++++++ .../bfcl/test_evaluator_comprehensive.py | 203 ++++++++++++++++++ .../byob/test_evaluator_comprehensive.py | 167 ++++++++++++++ .../tooltalk/test_evaluator_comprehensive.py | 144 +++++++++++++ 6 files changed, 669 insertions(+), 16 deletions(-) create mode 100644 packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py create mode 100644 packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py create mode 100644 packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py create mode 100644 packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py index 5bd1b50ad4..cfd5d7b514 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py @@ -55,8 +55,15 @@ def _extract_function_call(raw_output: str) -> str: if converted: return converted + # If the whole output looks like Python code with imports, extract calls first + stripped_output = raw_output.strip() + if stripped_output.startswith("import ") or stripped_output.startswith("from "): + calls = _extract_calls_from_code(stripped_output) + if calls: + return calls + # Try to find lines that look like function calls (name(...)) - lines = raw_output.strip().split('\n') + lines = stripped_output.split('\n') func_call_lines = [] for line in lines: stripped = line.strip() @@ -74,18 +81,6 @@ def _extract_function_call(raw_output: str) -> str: return func_call_lines[0] return '[' + ', '.join(func_call_lines) + ']' - # If the whole output looks like Python code with imports, extract calls - if raw_output.strip().startswith("import ") or raw_output.strip().startswith("from "): - calls = _extract_calls_from_code(raw_output.strip()) - if calls: - return calls - - # If the whole output looks like Python code with imports, extract calls - if raw_output.strip().startswith("import ") or raw_output.strip().startswith("from "): - calls = _extract_calls_from_code(raw_output.strip()) - if calls: - return calls - # Fallback: return as-is and let the AST parser try return raw_output diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py index 358fbbf467..8f01272e43 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py @@ -72,14 +72,21 @@ def _evaluate_single(item: EvalInputItem, database_dir: str) -> EvalOutputItem: from tooltalk.evaluation.tool_executor import ToolExecutor # output_obj contains the conversation JSON with predictions added by the workflow - if item.output_obj is None: + if not item.output_obj: return EvalOutputItem( id=item.id, score=0.0, - reasoning={"error": "No workflow output (output_obj is None)"}, + reasoning={"error": "No workflow output (output_obj is empty or None)"}, ) - conversation_with_predictions = json.loads(item.output_obj) + try: + conversation_with_predictions = json.loads(item.output_obj) + except (json.JSONDecodeError, TypeError) as e: + return EvalOutputItem( + id=item.id, + score=0.0, + reasoning={"error": f"Invalid JSON in output_obj: {e}"}, + ) # Use ToolTalk's ToolExecutor to compute metrics tool_executor = ToolExecutor(init_database_dir=database_dir) diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py new file mode 100644 index 0000000000..a345dece47 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py @@ -0,0 +1,137 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Comprehensive tests for Agent Leaderboard TSQ evaluator.""" + +import json + +import pytest + +from nat.data_models.evaluator import EvalInputItem +from nat.plugins.benchmarks.agent_leaderboard.evaluator import _evaluate_single + + +def _make_item(expected_tools, predicted_tools, via_input_obj=False): + """Create a test item. If via_input_obj, put expected_tool_calls in input_obj instead of full_dataset_entry.""" + expected_calls = [{"tool": t, "parameters": {}} for t in expected_tools] + predicted_calls = [{"tool": t, "parameters": {}} for t in predicted_tools] + + entry = { + "id": "test_001", + "question": json.dumps({"expected_tool_calls": expected_calls}), + "expected_tool_calls": expected_calls if not via_input_obj else [], + } + + return EvalInputItem( + id="test_001", + input_obj=json.dumps({"expected_tool_calls": expected_calls}) if via_input_obj else "{}", + expected_output_obj=json.dumps(expected_calls), + output_obj=json.dumps(predicted_calls), + full_dataset_entry=entry, + ) + + +class TestWeightedScoring: + + def test_tool_weight_only(self): + """tool_weight=1.0, parameter_weight=0.0 → score = tool_f1.""" + item = _make_item(["tool_a"], ["tool_a"]) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + assert result.score == 1.0 + + def test_parameter_weight_only(self): + """tool_weight=0.0, parameter_weight=1.0 → score = param_accuracy (placeholder=1.0).""" + item = _make_item(["tool_a"], ["wrong_tool"]) + result = _evaluate_single(item, tool_weight=0.0, parameter_weight=1.0) + assert result.score == 1.0 # param_accuracy placeholder is always 1.0 + + def test_mixed_weights(self): + """50/50 weighting.""" + item = _make_item(["tool_a"], ["tool_a"]) + result = _evaluate_single(item, tool_weight=0.5, parameter_weight=0.5) + # tool_f1=1.0, param=1.0 → 0.5*1.0 + 0.5*1.0 = 1.0 + assert result.score == 1.0 + + def test_mixed_weights_partial_match(self): + item = _make_item(["tool_a", "tool_b"], ["tool_a", "tool_c"]) + result = _evaluate_single(item, tool_weight=0.6, parameter_weight=0.4) + # tool_f1: precision=0.5, recall=0.5, f1=0.5 + # param=1.0 (placeholder) + # score = 0.6*0.5 + 0.4*1.0 = 0.7 + assert result.score == pytest.approx(0.7) + + +class TestInputObjFallback: + """Verify expected_tool_calls are found via input_obj when not in full_dataset_entry.""" + + def test_reads_from_input_obj(self): + item = _make_item(["tool_a"], ["tool_a"], via_input_obj=True) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + assert result.score == 1.0 + assert result.reasoning["expected_tools"] == ["toola"] + + +class TestReasoningFields: + """Verify all reasoning dict fields are present and correct.""" + + def test_all_fields_present(self): + item = _make_item(["get_balance", "transfer"], ["get_balance"]) + result = _evaluate_single(item, tool_weight=1.0, parameter_weight=0.0) + r = result.reasoning + + assert "tool_selection_f1" in r + assert "parameter_accuracy" in r + assert "predicted_tools" in r + assert "expected_tools" in r + assert "num_predicted" in r + assert "num_expected" in r + assert r["num_predicted"] == 1 + assert r["num_expected"] == 2 + assert sorted(r["predicted_tools"]) == ["getbalance"] + assert sorted(r["expected_tools"]) == ["getbalance", "transfer"] + + def test_f1_precision_recall_math(self): + """2 expected, 3 predicted, 1 overlap → precision=1/3, recall=1/2, F1=2/5.""" + item = _make_item(["a", "b"], ["a", "c", "d"]) + result = _evaluate_single(item, 1.0, 0.0) + # precision = 1/3, recall = 1/2, f1 = 2*(1/3)*(1/2)/((1/3)+(1/2)) = 2/5 = 0.4 + assert result.reasoning["tool_selection_f1"] == pytest.approx(0.4) + + +class TestEdgeCases: + + def test_malformed_json_output(self): + entry = {"expected_tool_calls": [{"tool": "t", "parameters": {}}]} + item = EvalInputItem( + id="bad", input_obj="{}", expected_output_obj="[]", + output_obj="not json", full_dataset_entry=entry, + ) + result = _evaluate_single(item, 1.0, 0.0) + assert result.score == 0.0 + + def test_output_is_dict_not_list(self): + entry = {"expected_tool_calls": [{"tool": "t", "parameters": {}}]} + item = EvalInputItem( + id="bad", input_obj="{}", expected_output_obj="[]", + output_obj='{"tool": "t"}', full_dataset_entry=entry, + ) + result = _evaluate_single(item, 1.0, 0.0) + # dict is not a list → predicted = [] → score 0 + assert result.score == 0.0 + + def test_duplicate_predicted_tools(self): + """Duplicate predictions shouldn't inflate precision (set-based comparison).""" + item = _make_item(["tool_a"], ["tool_a", "tool_a", "tool_a"]) + result = _evaluate_single(item, 1.0, 0.0) + assert result.score == 1.0 # Set-based: {tool_a} matches {tool_a} diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py new file mode 100644 index 0000000000..af008b1f97 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py @@ -0,0 +1,203 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Comprehensive evaluator tests covering all BFCL scoring paths.""" + +import json + +import pytest + +try: + from bfcl.eval_checker.ast_eval.ast_checker import ast_checker + _HAS_BFCL = True +except ImportError: + _HAS_BFCL = False + +pytestmark = pytest.mark.skipif(not _HAS_BFCL, reason="bfcl not installed") + +from nat.data_models.evaluator import EvalInputItem +from nat.plugins.benchmarks.bfcl.evaluator import ( + _evaluate_single, + _extract_function_call, + _try_convert_json_to_call, + _extract_calls_from_code, +) + + +def _make_item(entry, answer, output): + return EvalInputItem( + id=entry["id"], input_obj=json.dumps(entry), + expected_output_obj=json.dumps(answer), + output_obj=output, full_dataset_entry=entry, + ) + + +def _simple_entry(): + return { + "id": "simple_0", + "question": [[{"role": "user", "content": "Calculate area"}]], + "function": [{ + "name": "calc_area", + "description": "Calculate area", + "parameters": { + "type": "dict", + "properties": {"base": {"type": "integer"}, "height": {"type": "integer"}}, + "required": ["base", "height"], + }, + }], + } + + +def _simple_answer(): + return {"id": "simple_0", "ground_truth": [{"calc_area": {"base": [10], "height": [5]}}]} + + +class TestIrrelevanceMode: + """Tests for irrelevance test category — model should NOT produce function calls.""" + + def test_no_function_call_scores_1(self): + entry = _simple_entry() + answer = {"id": "simple_0", "ground_truth": []} + item = _make_item(entry, answer, "I cannot help with that request.") + result = _evaluate_single(item, "irrelevance", "Python") + assert result.score == 1.0 + + def test_valid_function_call_scores_0(self): + entry = _simple_entry() + answer = {"id": "simple_0", "ground_truth": []} + item = _make_item(entry, answer, "calc_area(base=10, height=5)") + result = _evaluate_single(item, "irrelevance", "Python") + assert result.score == 0.0 + + def test_garbage_output_scores_1(self): + """Unparseable output = no function call = correct for irrelevance.""" + entry = _simple_entry() + answer = {"id": "simple_0", "ground_truth": []} + item = _make_item(entry, answer, "Sorry, I don't know how to do that.") + result = _evaluate_single(item, "irrelevance", "Python") + assert result.score == 1.0 + + +class TestRelevanceMode: + """Tests for relevance test category — model SHOULD produce a function call.""" + + def test_valid_function_call_scores_1(self): + entry = _simple_entry() + answer = {"id": "simple_0", "ground_truth": []} + item = _make_item(entry, answer, "calc_area(base=10, height=5)") + result = _evaluate_single(item, "live_relevance", "Python") + assert result.score == 1.0 + + def test_no_function_call_scores_0(self): + entry = _simple_entry() + answer = {"id": "simple_0", "ground_truth": []} + item = _make_item(entry, answer, "I'm not sure what you need.") + result = _evaluate_single(item, "live_relevance", "Python") + assert result.score == 0.0 + + +class TestParallelCategory: + """Tests for parallel test category — multiple function calls in one response.""" + + def test_parallel_calls_scored(self): + entry = { + "id": "parallel_0", + "question": [[{"role": "user", "content": "Get area and perimeter"}]], + "function": [ + {"name": "calc_area", "description": "Area", "parameters": { + "type": "dict", "properties": {"x": {"type": "integer"}}, "required": ["x"]}}, + {"name": "calc_perimeter", "description": "Perimeter", "parameters": { + "type": "dict", "properties": {"x": {"type": "integer"}}, "required": ["x"]}}, + ], + } + answer = {"id": "parallel_0", "ground_truth": [ + {"calc_area": {"x": [5]}}, + {"calc_perimeter": {"x": [5]}}, + ]} + item = _make_item(entry, answer, "[calc_area(x=5), calc_perimeter(x=5)]") + result = _evaluate_single(item, "parallel", "Python") + assert result.score == 1.0 + + +class TestTryConvertJsonToCall: + """Tests for JSON tool-call format conversion.""" + + def test_converts_json_with_name_and_parameters(self): + text = '{"name": "func", "parameters": {"x": 10}}' + assert _try_convert_json_to_call(text) == "func(x=10)" + + def test_converts_json_with_arguments_key(self): + text = '{"name": "func", "arguments": {"a": 1, "b": 2}}' + result = _try_convert_json_to_call(text) + assert "func(" in result + assert "a=1" in result + assert "b=2" in result + + def test_returns_none_for_non_tool_json(self): + assert _try_convert_json_to_call('{"key": "value"}') is None + + def test_returns_none_for_invalid_json(self): + assert _try_convert_json_to_call("not json at all") is None + + def test_returns_none_for_list(self): + assert _try_convert_json_to_call("[1, 2, 3]") is None + + +class TestExtractCallsFromCode: + """Tests for extracting function calls from Python code blocks.""" + + def test_extracts_assigned_call(self): + code = "import math\nresult = math.hypot(4, 5)\nprint(result)" + result = _extract_calls_from_code(code) + assert result == "math.hypot(4, 5)" + + def test_extracts_bare_call(self): + code = "calculate_area(base=10, height=5)" + result = _extract_calls_from_code(code) + assert result == "calculate_area(base=10, height=5)" + + def test_skips_imports_and_prints(self): + code = "import math\nfrom os import path\nresult = func(x=1)\nprint(result)" + result = _extract_calls_from_code(code) + assert result == "func(x=1)" + + def test_returns_none_for_no_calls(self): + code = "import math\nprint('hello')" + result = _extract_calls_from_code(code) + assert result is None + + def test_multiple_calls(self): + code = "a = func_a(x=1)\nb = func_b(y=2)" + result = _extract_calls_from_code(code) + assert "func_a(x=1)" in result + assert "func_b(y=2)" in result + + +class TestExtractFunctionCallEdgeCases: + """Additional edge cases for the extraction pipeline.""" + + def test_json_code_block(self): + raw = '```json\n{"name": "func", "parameters": {"x": 10}}\n```' + assert _extract_function_call(raw) == "func(x=10)" + + def test_python_code_with_imports(self): + raw = "import math\nresult = math.factorial(5)\nprint(result)" + result = _extract_function_call(raw) + assert "math.factorial(5)" in result + + def test_tools_prefix_in_code_block(self): + raw = "```python\ntools.func(x=1)\n```" + # Code block extraction returns "tools.func(x=1)", then func call extraction strips it + result = _extract_function_call(raw) + assert "func(x=1)" in result or "tools.func(x=1)" in result diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py new file mode 100644 index 0000000000..9e0a8f0a13 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py @@ -0,0 +1,167 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Comprehensive tests for BYOB evaluator — covers score_field, metadata, error handling.""" + +import json + +import pytest + +try: + from nemo_evaluator.contrib.byob.decorators import ScorerInput + from nemo_evaluator.contrib.byob.scorers import exact_match, contains, f1_token + _HAS_BYOB = True +except ImportError: + _HAS_BYOB = False + +pytestmark = pytest.mark.skipif(not _HAS_BYOB, reason="nemo_evaluator BYOB not installed") + +from nat.data_models.evaluator import EvalInputItem +from nat.plugins.benchmarks.byob.evaluator import _evaluate_single + + +class TestScoreFieldSelection: + """Verify score_field selects the correct key from scorer output.""" + + def test_default_correct_field(self): + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="hello", + output_obj="hello", full_dataset_entry={"target": "hello"}, + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + assert result.score == 1.0 + + def test_f1_score_field(self): + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="the quick brown fox", + output_obj="the quick brown dog", + full_dataset_entry={"target": "the quick brown fox"}, + ) + result = _evaluate_single(item, f1_token, "target", "f1", {}) + assert 0.0 < result.score < 1.0 + assert "f1" in result.reasoning + assert "precision" in result.reasoning + assert "recall" in result.reasoning + + def test_precision_score_field(self): + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="a b c", + output_obj="a b c d e", + full_dataset_entry={"target": "a b c"}, + ) + result = _evaluate_single(item, f1_token, "target", "precision", {}) + # precision = 3/5 = 0.6 + assert result.score == pytest.approx(0.6) + + def test_missing_score_field_returns_0(self): + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="hello", + output_obj="hello", full_dataset_entry={"target": "hello"}, + ) + result = _evaluate_single(item, exact_match, "target", "nonexistent_field", {}) + assert result.score == 0.0 + + def test_boolean_score_converted_to_float(self): + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="yes", + output_obj="yes", full_dataset_entry={"target": "yes"}, + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + assert isinstance(result.score, float) + assert result.score == 1.0 + + +class TestMetadataPassthrough: + """Verify full_dataset_entry is passed as metadata to the scorer.""" + + def test_metadata_available_to_scorer(self): + """Custom scorer that reads metadata.""" + def metadata_checker(sample: ScorerInput) -> dict: + has_extra = "extra_field" in sample.metadata + return {"correct": has_extra} + + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="x", + output_obj="x", + full_dataset_entry={"target": "x", "extra_field": "present"}, + ) + result = _evaluate_single(item, metadata_checker, "target", "correct", {}) + assert result.score == 1.0 + + def test_string_full_entry_parsed_to_dict(self): + """full_dataset_entry as JSON string should be parsed.""" + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="hello", + output_obj="hello", + full_dataset_entry=json.dumps({"target": "hello", "category": "test"}), + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + assert result.score == 1.0 + + +class TestExtraConfig: + """Verify extra_config is passed to the scorer.""" + + def test_config_available_to_scorer(self): + def config_scorer(sample: ScorerInput) -> dict: + threshold = sample.config.get("threshold", 0.5) + return {"correct": len(sample.response) > threshold} + + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="x", + output_obj="hello world", + full_dataset_entry={"target": "x"}, + ) + result = _evaluate_single(item, config_scorer, "target", "correct", {"threshold": 3}) + assert result.score == 1.0 + + +class TestScorerErrors: + """Verify error handling when the scorer raises exceptions.""" + + def test_scorer_exception_returns_0(self): + def bad_scorer(sample: ScorerInput) -> dict: + raise ValueError("Scorer crashed!") + + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="x", + output_obj="hello", full_dataset_entry={"target": "x"}, + ) + result = _evaluate_single(item, bad_scorer, "target", "correct", {}) + assert result.score == 0.0 + assert "Scorer failed" in result.reasoning["error"] + + +class TestTargetParsing: + """Verify target values are correctly parsed from expected_output_obj.""" + + def test_string_target(self): + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj="Paris", + output_obj="Paris", full_dataset_entry={"target": "Paris"}, + ) + result = _evaluate_single(item, exact_match, "target", "correct", {}) + assert result.score == 1.0 + + def test_json_target_parsed(self): + """JSON-encoded target should be parsed.""" + def list_scorer(sample: ScorerInput) -> dict: + return {"correct": isinstance(sample.target, list)} + + item = EvalInputItem( + id="0", input_obj="{}", expected_output_obj='["a", "b"]', + output_obj="x", full_dataset_entry={"target": ["a", "b"]}, + ) + result = _evaluate_single(item, list_scorer, "target", "correct", {}) + assert result.score == 1.0 diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py new file mode 100644 index 0000000000..0b56a5b486 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py @@ -0,0 +1,144 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Comprehensive tests for ToolTalk evaluator — covers all metric fields and edge cases.""" + +import json +import os + +import pytest + +from nat.data_models.evaluator import EvalInputItem + +try: + import tooltalk + _DB_DIR = os.path.join(os.path.dirname(tooltalk.__file__), "data", "databases") + _HAS_TOOLTALK = os.path.isdir(_DB_DIR) +except ImportError: + _HAS_TOOLTALK = False + +pytestmark = pytest.mark.skipif(not _HAS_TOOLTALK, reason="tooltalk not installed") + +from nat.plugins.benchmarks.tooltalk.evaluator import _evaluate_single + + +def _alarm_conv(predictions): + """Build a standard AddAlarm conversation with given predictions.""" + return { + "name": "test", "conversation_id": "test-001", + "suites_used": ["Alarm"], "apis_used": ["AddAlarm"], + "scenario": "test", + "user": {"username": "testuser", "email": "t@t.com", "phone": "123-456-7890", + "name": "Test", "password": "pass", "session_token": "tok-123"}, + "metadata": {"location": "NY", "timestamp": "2023-09-11 13:00:00", + "session_token": "tok-123", "username": "testuser"}, + "conversation": [ + {"index": 0, "role": "user", "text": "Set alarm for 6:30"}, + {"index": 1, "role": "assistant", "text": "Done.", + "apis": [{"request": {"api_name": "AddAlarm", + "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, + "response": {"alarm_id": "5bff-dd80"}, "exception": None}], + "predictions": predictions}, + ], + } + + +def _make_item(conv): + return EvalInputItem( + id="test-001", input_obj=json.dumps(conv), + expected_output_obj=json.dumps(conv), + output_obj=json.dumps(conv), full_dataset_entry=conv, + ) + + +class TestAllMetricFields: + """Verify every metric field in the reasoning dict.""" + + def test_perfect_match_all_fields(self): + preds = [ + {"role": "api", "request": {"api_name": "AddAlarm", + "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, + "response": {"alarm_id": "5bff-dd80"}, "exception": None}, + {"role": "assistant", "text": "Done."}, + ] + result = _evaluate_single(_make_item(_alarm_conv(preds)), _DB_DIR) + r = result.reasoning + + assert r["predictions"] == 1 + assert r["ground_truths"] == 1 + assert r["matches"] == 1 + assert r["recall"] == 1.0 + assert r["actions"] == 1 + assert r["valid_actions"] == 1 + assert r["bad_actions"] == 0 + assert r["action_precision"] == 1.0 + assert r["bad_action_rate"] == 0.0 + assert r["success"] == 1.0 + assert r["soft_success"] == 1.0 + + def test_no_api_predictions_all_fields(self): + preds = [{"role": "assistant", "text": "I can't do that."}] + result = _evaluate_single(_make_item(_alarm_conv(preds)), _DB_DIR) + r = result.reasoning + + assert r["predictions"] == 0 + assert r["ground_truths"] == 1 + assert r["matches"] == 0 + assert r["recall"] == 0.0 + assert r["bad_action_rate"] == 0.0 + assert r["success"] == 0.0 + + def test_soft_success_calculation(self): + """3 predictions: 1 match + 2 bad actions → soft_success = recall*(1-bad_rate).""" + preds = [ + {"role": "api", "request": {"api_name": "AddAlarm", + "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, + "response": {"alarm_id": "5bff-dd80"}, "exception": None}, + {"role": "api", "request": {"api_name": "AddAlarm", + "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, + "response": {"alarm_id": "aaaa-bbbb"}, "exception": None}, + {"role": "api", "request": {"api_name": "AddAlarm", + "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, + "response": {"alarm_id": "cccc-dddd"}, "exception": None}, + {"role": "assistant", "text": "Done."}, + ] + result = _evaluate_single(_make_item(_alarm_conv(preds)), _DB_DIR) + r = result.reasoning + + assert r["recall"] == 1.0 + assert r["bad_actions"] == 2 + assert r["bad_action_rate"] == pytest.approx(2 / 3) + assert r["soft_success"] == pytest.approx(1.0 * (1 - 2 / 3)) + assert r["success"] == 0.0 # bad_action_rate > 0 + + +class TestMalformedInput: + """Edge cases for malformed evaluator input.""" + + def test_invalid_json_output(self): + item = EvalInputItem( + id="bad", input_obj="{}", expected_output_obj="{}", + output_obj="not valid json at all", full_dataset_entry={}, + ) + result = _evaluate_single(item, _DB_DIR) + assert result.score == 0.0 + assert "error" in result.reasoning + + def test_empty_string_output(self): + item = EvalInputItem( + id="empty", input_obj="{}", expected_output_obj="{}", + output_obj="", full_dataset_entry={}, + ) + result = _evaluate_single(item, _DB_DIR) + assert result.score == 0.0 From 3bebc05d1cc4d5803acd7f905f1848dcddf269b9 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 12:24:53 -0700 Subject: [PATCH 04/10] pre-commit check cleanup Signed-off-by: Bryan Bednarski --- examples/benchmarks/byob/README.md | 4 +- .../benchmarks/agent_leaderboard/config.py | 8 +- .../benchmarks/agent_leaderboard/dataset.py | 12 +- .../benchmarks/agent_leaderboard/evaluator.py | 15 +- .../benchmarks/agent_leaderboard/workflow.py | 33 ++-- .../src/nat/plugins/benchmarks/bfcl/config.py | 19 ++- .../nat/plugins/benchmarks/bfcl/evaluator.py | 56 +++++-- .../plugins/benchmarks/bfcl/workflow_ast.py | 26 ++-- .../plugins/benchmarks/bfcl/workflow_react.py | 33 ++-- .../src/nat/plugins/benchmarks/byob/config.py | 19 +-- .../nat/plugins/benchmarks/byob/dataset.py | 12 +- .../nat/plugins/benchmarks/byob/evaluator.py | 29 +++- .../nat/plugins/benchmarks/tooltalk/config.py | 12 +- .../plugins/benchmarks/tooltalk/evaluator.py | 9 +- .../plugins/benchmarks/tooltalk/workflow.py | 63 ++++---- .../tests/agent_leaderboard/test_dataset.py | 54 ++++--- .../tests/agent_leaderboard/test_evaluator.py | 19 ++- .../test_evaluator_comprehensive.py | 14 +- .../tests/bfcl/test_dataset.py | 20 ++- .../tests/bfcl/test_evaluator.py | 27 ++-- .../bfcl/test_evaluator_comprehensive.py | 91 +++++++---- .../tests/bfcl/test_integration.py | 29 +++- .../tests/bfcl/test_regression.py | 2 - .../tests/bfcl/test_tool_intent_stubs.py | 22 ++- .../tests/byob/fixtures/sample_benchmark.py | 20 ++- .../tests/byob/test_evaluator.py | 56 ++++--- .../byob/test_evaluator_comprehensive.py | 81 +++++++--- .../tests/byob/test_integration.py | 66 ++++---- .../tests/tooltalk/conftest.py | 1 - .../tests/tooltalk/test_dataset.py | 37 +++-- .../tests/tooltalk/test_evaluator.py | 33 ++-- .../tooltalk/test_evaluator_comprehensive.py | 142 +++++++++++++----- .../tests/tooltalk/test_integration.py | 15 +- .../tests/tooltalk/test_regression.py | 129 +++++++++++----- ..._per_user_function_group_eval_isolation.py | 37 +++-- 35 files changed, 806 insertions(+), 439 deletions(-) diff --git a/examples/benchmarks/byob/README.md b/examples/benchmarks/byob/README.md index 8a436a9770..19088e4b92 100644 --- a/examples/benchmarks/byob/README.md +++ b/examples/benchmarks/byob/README.md @@ -19,7 +19,7 @@ limitations under the License. **Complexity:** 🟡 Intermediate -Run [NeMo Evaluator BYOB](https://docs.nvidia.com/nemo/evaluator/) benchmarks directly on NAT agent workflows — without re-implementing the dataset loader or scorer logic. +Run [NeMo Evaluator BYOB](https://docs.nvidia.com/nemo/evaluator/latest/) benchmarks directly on NAT agent workflows — without re-implementing the dataset loader or scorer logic. ## Why BYOB in NAT? @@ -197,7 +197,7 @@ Average score: 0.667 ## Built-in Scorers Reference -BYOB scorers come from the [NeMo Evaluator](https://docs.nvidia.com/nemo/evaluator/) framework (`nemo_evaluator.contrib.byob.scorers`). They are standard NLP evaluation metrics packaged as simple Python functions that accept a `ScorerInput` and return a dict of metric values. When you use BYOB through NAT, the scorer runs in-process against the workflow's output — NAT handles the LLM calls and the scorer only sees the final `(response, target)` pair. +BYOB scorers come from the [NeMo Evaluator](https://docs.nvidia.com/nemo/evaluator/latest/) framework (`nemo_evaluator.contrib.byob.scorers`). They are standard NLP evaluation metrics packaged as simple Python functions that accept a `ScorerInput` and return a dict of metric values. When you use BYOB through NAT, the scorer runs in-process against the workflow's output — NAT handles the LLM calls and the scorer only sees the final `(response, target)` pair. You can use any built-in scorer directly, compose them with `any_of()` / `all_of()`, or write your own from scratch. The only requirement is the signature: `def scorer(sample: ScorerInput) -> dict`. diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py index 713b6370fc..d321680fd2 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py @@ -59,11 +59,9 @@ class AgentLeaderboardWorkflowConfig(AgentBaseConfig, name="agent_leaderboard_wo description="Maximum tool-calling steps per scenario", ) system_prompt: str | None = Field( - default=( - "You are a tool-calling agent. Select the correct tools to handle the user's request.\n" - "Focus on selecting the RIGHT TOOL for each step. Use placeholder values for parameters.\n" - "Tool responses are simulated — focus on tool choice, not data quality." - ), + default=("You are a tool-calling agent. Select the correct tools to handle the user's request.\n" + "Focus on selecting the RIGHT TOOL for each step. Use placeholder values for parameters.\n" + "Tool responses are simulated — focus on tool choice, not data quality."), description="System prompt for the agent", ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py index 1baff64f54..2740d1b050 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/dataset.py @@ -73,9 +73,7 @@ def _derive_expected_tool_calls(user_goals: list[str], tools: list[dict]) -> lis tool_name_lower = tool_name.lower() for keyword, patterns in keyword_mappings.items(): - if keyword in goal_lower and any( - p in tool_name_lower or p in tool_desc for p in patterns - ): + if keyword in goal_lower and any(p in tool_name_lower or p in tool_desc for p in patterns): if tool_name not in seen: seen.add(tool_name) expected.append({"tool": tool_name, "parameters": {}}) @@ -165,13 +163,9 @@ def _download_from_huggingface(domains: list[str]) -> list[dict]: @register_dataset_loader(config_type=AgentLeaderboardDatasetConfig) -async def register_agent_leaderboard_dataset_loader( - config: AgentLeaderboardDatasetConfig, builder: EvalBuilder -): +async def register_agent_leaderboard_dataset_loader(config: AgentLeaderboardDatasetConfig, builder: EvalBuilder): yield DatasetLoaderInfo( config=config, - load_fn=lambda fp, **kw: load_agent_leaderboard_dataset( - fp, domains=config.domains, limit=config.limit, **kw - ), + load_fn=lambda fp, **kw: load_agent_leaderboard_dataset(fp, domains=config.domains, limit=config.limit, **kw), description="Galileo Agent Leaderboard v2 dataset loader", ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py index f166b35fd4..1ffff3c76e 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py @@ -24,7 +24,10 @@ from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo from nat.cli.register_workflow import register_evaluator -from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem +from nat.data_models.evaluator import EvalInput +from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalOutput +from nat.data_models.evaluator import EvalOutputItem from .config import TSQEvaluatorConfig @@ -45,7 +48,8 @@ def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: """Evaluate tool selection quality for a single scenario.""" if item.output_obj is None: return EvalOutputItem( - id=item.id, score=0.0, + id=item.id, + score=0.0, reasoning={"error": "No workflow output"}, ) @@ -75,7 +79,8 @@ def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: # If not found, try parsing the 'question' field (which contains the serialized entry) if not expected and "question" in full_entry: try: - question_data = json.loads(full_entry["question"]) if isinstance(full_entry["question"], str) else full_entry["question"] + question_data = json.loads(full_entry["question"]) if isinstance(full_entry["question"], + str) else full_entry["question"] if isinstance(question_data, dict): expected = question_data.get("expected_tool_calls", []) except (json.JSONDecodeError, TypeError): @@ -133,7 +138,9 @@ async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: except Exception as e: logger.exception("Error evaluating TSQ for item %s: %s", item.id, e) output_item = EvalOutputItem( - id=item.id, score=0.0, reasoning={"error": str(e)}, + id=item.id, + score=0.0, + reasoning={"error": str(e)}, ) eval_output_items.append(output_item) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py index d0b3066882..850f6807fa 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py @@ -28,12 +28,9 @@ from nat.builder.function_info import FunctionInfo from nat.cli.register_workflow import register_function -from ..bfcl.tool_intent_stubs import ( - ToolIntentBuffer, - clear_global_intents, - get_global_intents, - set_current_scenario_id, -) +from ..bfcl.tool_intent_stubs import ToolIntentBuffer +from ..bfcl.tool_intent_stubs import clear_global_intents +from ..bfcl.tool_intent_stubs import set_current_scenario_id from .config import AgentLeaderboardWorkflowConfig logger = logging.getLogger(__name__) @@ -65,7 +62,10 @@ def _tool_schema_to_openai(tool: dict) -> dict: framework_wrappers=[LLMFrameworkEnum.LANGCHAIN], ) async def agent_leaderboard_workflow(config: AgentLeaderboardWorkflowConfig, builder: Builder): - from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage + from langchain_core.messages import AIMessage + from langchain_core.messages import HumanMessage + from langchain_core.messages import SystemMessage + from langchain_core.messages import ToolMessage llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) @@ -80,7 +80,7 @@ async def _run(input_json: str) -> str: # Scenario isolation scenario_id = f"al_{hashlib.md5(input_json[:200].encode()).hexdigest()[:12]}" - token = set_current_scenario_id(scenario_id) + _token = set_current_scenario_id(scenario_id) clear_global_intents(scenario_id) intent_buffer = ToolIntentBuffer() @@ -110,14 +110,15 @@ async def _run(input_json: str) -> str: # Canned response canned = f"Successfully executed {name}. Operation completed." - messages.append(AIMessage( - content="", - tool_calls=[{ - "name": name, - "args": args, - "id": tc.get("id", f"call_{step}_{name}"), - }], - )) + messages.append( + AIMessage( + content="", + tool_calls=[{ + "name": name, + "args": args, + "id": tc.get("id", f"call_{step}_{name}"), + }], + )) messages.append(ToolMessage( content=canned, tool_call_id=tc.get("id", f"call_{step}_{name}"), diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py index b0c9b9ad7c..2f21119dcf 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py @@ -15,7 +15,6 @@ """Configuration types for the BFCL benchmark.""" from collections.abc import Callable -from typing import Literal from pydantic import Field @@ -23,13 +22,21 @@ from nat.data_models.dataset_handler import EvalDatasetBaseConfig from nat.data_models.evaluator import EvaluatorBaseConfig - # Valid BFCL v3 single-turn AST test categories BFCL_AST_CATEGORIES = [ - "simple", "multiple", "parallel", "parallel_multiple", - "java", "javascript", - "live_simple", "live_multiple", "live_parallel", "live_parallel_multiple", - "irrelevance", "live_irrelevance", "live_relevance", + "simple", + "multiple", + "parallel", + "parallel_multiple", + "java", + "javascript", + "live_simple", + "live_multiple", + "live_parallel", + "live_parallel_multiple", + "irrelevance", + "live_irrelevance", + "live_relevance", ] diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py index cfd5d7b514..86519ebe3a 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py @@ -24,7 +24,10 @@ from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo from nat.cli.register_workflow import register_evaluator -from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem +from nat.data_models.evaluator import EvalInput +from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalOutput +from nat.data_models.evaluator import EvalOutputItem from .config import BFCLEvaluatorConfig @@ -133,17 +136,20 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> if item.output_obj is None: return EvalOutputItem( - id=item.id, score=0.0, + id=item.id, + score=0.0, reasoning={"error": "No workflow output (output_obj is None)"}, ) # Parse the test entry and ground truth try: entry = json.loads(item.input_obj) if isinstance(item.input_obj, str) else item.input_obj - answer = json.loads(item.expected_output_obj) if isinstance(item.expected_output_obj, str) else item.expected_output_obj + answer = json.loads(item.expected_output_obj) if isinstance(item.expected_output_obj, + str) else item.expected_output_obj except (json.JSONDecodeError, TypeError) as e: return EvalOutputItem( - id=item.id, score=0.0, + id=item.id, + score=0.0, reasoning={"error": f"Failed to parse input/answer: {e}"}, ) @@ -159,9 +165,11 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> # If decoding succeeds and produces non-empty output, it's a failure if decoded and any(decoded): return EvalOutputItem( - id=item.id, score=0.0, - reasoning={"error": "Model produced function call for irrelevance test", - "decoded": str(decoded)}, + id=item.id, + score=0.0, + reasoning={ + "error": "Model produced function call for irrelevance test", "decoded": str(decoded) + }, ) except Exception: pass # Decode failure = success for irrelevance @@ -176,7 +184,8 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> except Exception: pass return EvalOutputItem( - id=item.id, score=0.0, + id=item.id, + score=0.0, reasoning={"error": "Model failed to produce function call for relevance test"}, ) @@ -185,19 +194,29 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> decoded_output = default_decode_ast_prompting(model_output_raw, language) except Exception as e: return EvalOutputItem( - id=item.id, score=0.0, - reasoning={"error": f"AST decode failed: {e}", "raw_output": model_output_raw[:500]}, + id=item.id, + score=0.0, + reasoning={ + "error": f"AST decode failed: {e}", "raw_output": model_output_raw[:500] + }, ) try: checker_result = ast_checker( - func_description, decoded_output, possible_answer, - language, test_category, "nat_benchmark", + func_description, + decoded_output, + possible_answer, + language, + test_category, + "nat_benchmark", ) except Exception as e: return EvalOutputItem( - id=item.id, score=0.0, - reasoning={"error": f"ast_checker failed: {e}", "decoded": str(decoded_output)[:500]}, + id=item.id, + score=0.0, + reasoning={ + "error": f"ast_checker failed: {e}", "decoded": str(decoded_output)[:500] + }, ) is_valid = checker_result.get("valid", False) @@ -226,7 +245,9 @@ async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: except Exception as e: logger.exception("Error evaluating BFCL item %s: %s", item.id, e) output_item = EvalOutputItem( - id=item.id, score=0.0, reasoning={"error": str(e)}, + id=item.id, + score=0.0, + reasoning={"error": str(e)}, ) eval_output_items.append(output_item) @@ -235,7 +256,10 @@ async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: logger.info( "BFCL evaluation complete: accuracy=%.3f (%d/%d) category=%s", - average_score, sum(1 for s in scores if s == 1.0), len(scores), config.test_category, + average_score, + sum(1 for s in scores if s == 1.0), + len(scores), + config.test_category, ) return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py index a3fef455a0..32fb9e266b 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py @@ -33,21 +33,25 @@ # System prompt matching BFCL's default AST prompting format # Source: bfcl.model_handler.constant.DEFAULT_SYSTEM_PROMPT -SYSTEM_PROMPT = """You are an expert in composing functions. You are given a question and a set of possible functions. Based on the question, you will need to make one or more function/tool calls to achieve the purpose. -If none of the functions can be used, point it out. If the given question lacks the parameters required by the function, also point it out. -You should only return the function calls in your response. - -If you decide to invoke any of the function(s), you MUST put it in the format of [func_name1(params_name1=params_value1, params_name2=params_value2...), func_name2(params)] -You SHOULD NOT include any other text in the response. - -Here is a list of functions in JSON format that you can invoke. -{functions_json} -""" +SYSTEM_PROMPT = ( # noqa: E501 — verbatim from bfcl.model_handler.constant.DEFAULT_SYSTEM_PROMPT + "You are an expert in composing functions. You are given a question and a set of possible " + "functions. Based on the question, you will need to make one or more function/tool calls to " + "achieve the purpose.\n" + "If none of the functions can be used, point it out. If the given question lacks the " + "parameters required by the function, also point it out.\n" + "You should only return the function calls in your response.\n\n" + "If you decide to invoke any of the function(s), you MUST put it in the format of " + "[func_name1(params_name1=params_value1, params_name2=params_value2...), func_name2(params)]\n" + "You SHOULD NOT include any other text in the response.\n\n" + "Here is a list of functions in JSON format that you can invoke.\n" + "{functions_json}\n" +) @register_function(config_type=BFCLASTWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def bfcl_ast_workflow(config: BFCLASTWorkflowConfig, builder: Builder): - from langchain_core.messages import HumanMessage, SystemMessage + from langchain_core.messages import HumanMessage + from langchain_core.messages import SystemMessage llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py index 928df7d362..8caa36f105 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py @@ -33,8 +33,10 @@ from nat.cli.register_workflow import register_function from nat.data_models.agent import AgentBaseConfig -from .tool_intent_stubs import ToolIntentBuffer, set_current_scenario_id, clear_global_intents -from .workflow_fc import _convert_bfcl_schema_to_openai, GORILLA_TO_OPENAPI +from .tool_intent_stubs import ToolIntentBuffer +from .tool_intent_stubs import clear_global_intents +from .tool_intent_stubs import set_current_scenario_id +from .workflow_fc import _convert_bfcl_schema_to_openai logger = logging.getLogger(__name__) @@ -56,7 +58,10 @@ class BFCLReActWorkflowConfig(AgentBaseConfig, name="bfcl_react_workflow"): @register_function(config_type=BFCLReActWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def bfcl_react_workflow(config: BFCLReActWorkflowConfig, builder: Builder): - from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage + from langchain_core.messages import AIMessage + from langchain_core.messages import HumanMessage + from langchain_core.messages import SystemMessage + from langchain_core.messages import ToolMessage llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) @@ -68,7 +73,7 @@ async def _run(input_json: str) -> str: # Set up scenario isolation for concurrent execution scenario_id = f"bfcl_{hashlib.md5(input_json[:200].encode()).hexdigest()[:12]}" - token = set_current_scenario_id(scenario_id) + _token = set_current_scenario_id(scenario_id) clear_global_intents(scenario_id) intent_buffer = ToolIntentBuffer() @@ -93,8 +98,7 @@ async def _run(input_json: str) -> str: # Build initial messages system_msg = SystemMessage( content="You are a helpful assistant. Use the provided tools to answer the user's request. " - "Think step by step about which tool(s) to call and with what parameters." - ) + "Think step by step about which tool(s) to call and with what parameters.") messages = [system_msg, HumanMessage(content=user_content)] # ReAct loop @@ -134,14 +138,15 @@ async def _run(input_json: str) -> str: canned = f"Successfully executed {name}. Operation completed." # Add the assistant message with tool call + tool response - messages.append(AIMessage( - content="", - tool_calls=[{ - "name": name, - "args": args, - "id": tc.get("id", f"call_{step}_{name}"), - }], - )) + messages.append( + AIMessage( + content="", + tool_calls=[{ + "name": name, + "args": args, + "id": tc.get("id", f"call_{step}_{name}"), + }], + )) messages.append(ToolMessage( content=canned, tool_call_id=tc.get("id", f"call_{step}_{name}"), diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py index 72612aaf05..d7ac605846 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/config.py @@ -15,7 +15,6 @@ """Configuration types for BYOB (Bring Your Own Benchmark) integration.""" from collections.abc import Callable -from typing import Any from pydantic import Field @@ -30,13 +29,9 @@ class BYOBDatasetConfig(EvalDatasetBaseConfig, name="byob"): and name are used to import the benchmark and access its dataset. """ - benchmark_module: str = Field( - description="Python module path or file path to the benchmark definition " - "(e.g. 'my_benchmarks.qa' or '/path/to/benchmark.py')", - ) - benchmark_name: str = Field( - description="Normalized benchmark name as registered with @benchmark decorator", - ) + benchmark_module: str = Field(description="Python module path or file path to the benchmark definition " + "(e.g. 'my_benchmarks.qa' or '/path/to/benchmark.py')", ) + benchmark_name: str = Field(description="Normalized benchmark name as registered with @benchmark decorator", ) limit: int | None = Field( default=None, description="Limit number of dataset samples (for testing)", @@ -58,12 +53,8 @@ class BYOBEvaluatorConfig(EvaluatorBaseConfig, name="byob_evaluator"): (safe for all built-in scorers like exact_match, contains, f1_token). """ - benchmark_module: str = Field( - description="Python module path or file path to the benchmark definition", - ) - benchmark_name: str = Field( - description="Normalized benchmark name", - ) + benchmark_module: str = Field(description="Python module path or file path to the benchmark definition", ) + benchmark_name: str = Field(description="Normalized benchmark name", ) score_field: str = Field( default="correct", description="Key in scorer output dict to use as the primary score " diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py index bbaa43ba86..c5b4680ac5 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/dataset.py @@ -47,8 +47,8 @@ def load_byob_dataset( The file_path parameter is required by NAT's DatasetHandler interface but is ignored — the dataset path comes from the benchmark definition. """ - from nemo_evaluator.contrib.byob.eval_logic import import_benchmark from nemo_evaluator.contrib.byob.dataset import load_dataset + from nemo_evaluator.contrib.byob.eval_logic import import_benchmark bench = import_benchmark(benchmark_module, benchmark_name) logger.info("Imported BYOB benchmark '%s' (dataset: %s)", bench.name, bench.dataset) @@ -59,8 +59,6 @@ def load_byob_dataset( rows = [] for i, sample in enumerate(samples): target = sample.get(bench.target_field, "") - # Use response_field for eval-only mode if present - response = sample.get(bench.response_field, "") if bench.response_field else "" rows.append({ "id": sample.get("id", str(i)), @@ -77,8 +75,10 @@ async def register_byob_dataset_loader(config: BYOBDatasetConfig, builder: EvalB yield DatasetLoaderInfo( config=config, load_fn=lambda fp, **kw: load_byob_dataset( - fp, benchmark_module=config.benchmark_module, - benchmark_name=config.benchmark_name, limit=config.limit, **kw, - ), + fp, + benchmark_module=config.benchmark_module, + benchmark_name=config.benchmark_name, + limit=config.limit, + **kw, ), description="BYOB benchmark dataset loader", ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py index 941c50b3a0..e20af28b29 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py @@ -25,7 +25,10 @@ from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo from nat.cli.register_workflow import register_evaluator -from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem +from nat.data_models.evaluator import EvalInput +from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalOutput +from nat.data_models.evaluator import EvalOutputItem from .config import BYOBEvaluatorConfig @@ -44,7 +47,8 @@ def _evaluate_single( if item.output_obj is None: return EvalOutputItem( - id=item.id, score=0.0, + id=item.id, + score=0.0, reasoning={"error": "No workflow output (output_obj is None)"}, ) @@ -79,7 +83,8 @@ def _evaluate_single( scores = scorer_fn(scorer_input) except Exception as e: return EvalOutputItem( - id=item.id, score=0.0, + id=item.id, + score=0.0, reasoning={"error": f"Scorer failed: {e}"}, ) @@ -97,7 +102,8 @@ async def byob_evaluator_function(config: BYOBEvaluatorConfig, builder: EvalBuil bench = import_benchmark(config.benchmark_module, config.benchmark_name) logger.info("BYOB evaluator loaded benchmark '%s' with scorer '%s'", - bench.name, getattr(bench.scorer_fn, '__name__', 'unknown')) + bench.name, + getattr(bench.scorer_fn, '__name__', 'unknown')) async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: eval_output_items = [] @@ -105,13 +111,18 @@ async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: for item in eval_input.eval_input_items: try: output_item = _evaluate_single( - item, bench.scorer_fn, bench.target_field, - config.score_field, bench.extra_config, + item, + bench.scorer_fn, + bench.target_field, + config.score_field, + bench.extra_config, ) except Exception as e: logger.exception("Error evaluating BYOB item %s: %s", item.id, e) output_item = EvalOutputItem( - id=item.id, score=0.0, reasoning={"error": str(e)}, + id=item.id, + score=0.0, + reasoning={"error": str(e)}, ) eval_output_items.append(output_item) @@ -120,7 +131,9 @@ async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: logger.info( "BYOB evaluation complete: avg_%s=%.3f (%d items)", - config.score_field, average_score, len(scores), + config.score_field, + average_score, + len(scores), ) return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py index a6227f9dc1..49313c5944 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py @@ -14,7 +14,6 @@ # limitations under the License. from collections.abc import Callable -from pathlib import Path from pydantic import Field @@ -31,8 +30,7 @@ class ToolTalkDatasetConfig(EvalDatasetBaseConfig, name="tooltalk"): """ database_dir: str = Field( - description="Path to ToolTalk database directory (contains Account.json, Alarm.json, etc.)", - ) + description="Path to ToolTalk database directory (contains Account.json, Alarm.json, etc.)", ) def parser(self) -> tuple[Callable, dict]: from .dataset import load_tooltalk_dataset @@ -46,9 +44,7 @@ class ToolTalkWorkflowConfig(AgentBaseConfig, name="tooltalk_workflow"): """ description: str = Field(default="ToolTalk Benchmark Workflow") - database_dir: str = Field( - description="Path to ToolTalk database directory", - ) + database_dir: str = Field(description="Path to ToolTalk database directory", ) api_mode: str = Field( default="all", description="Which API docs to include: 'exact' (only APIs in conversation), " @@ -70,6 +66,4 @@ class ToolTalkEvaluatorConfig(EvaluatorBaseConfig, name="tooltalk_evaluator"): Uses ToolTalk's built-in metrics: recall, action_precision, bad_action_rate, success. """ - database_dir: str = Field( - description="Path to ToolTalk database directory", - ) + database_dir: str = Field(description="Path to ToolTalk database directory", ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py index 8f01272e43..076b61420e 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py @@ -24,7 +24,10 @@ from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo from nat.cli.register_workflow import register_evaluator -from nat.data_models.evaluator import EvalInput, EvalInputItem, EvalOutput, EvalOutputItem +from nat.data_models.evaluator import EvalInput +from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalOutput +from nat.data_models.evaluator import EvalOutputItem from .config import ToolTalkEvaluatorConfig @@ -33,7 +36,6 @@ @register_evaluator(config_type=ToolTalkEvaluatorConfig) async def tooltalk_evaluator_function(config: ToolTalkEvaluatorConfig, builder: EvalBuilder): - from tooltalk.evaluation.tool_executor import ToolExecutor async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: eval_output_items = [] @@ -55,7 +57,8 @@ async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: logger.info( "ToolTalk evaluation complete: average_success=%.3f across %d conversations", - average_score, len(scores), + average_score, + len(scores), ) return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py index b3b9e74f36..5f544e9db7 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py @@ -44,22 +44,22 @@ def _build_tool_schemas(apis_used, disable_docs: bool = False) -> list[dict]: def _build_messages(conversation_history: list[dict], metadata: dict | None = None) -> list[dict]: """Convert ToolTalk conversation history to OpenAI chat messages format.""" - system_prompt = ( - "You are a helpful assistant. Here is some user data:" - "\nlocation: {location}" - "\ntimestamp: {timestamp}" - "\nusername (if logged in): {username}" - ) + system_prompt = ("You are a helpful assistant. Here is some user data:" + "\nlocation: {location}" + "\ntimestamp: {timestamp}" + "\nusername (if logged in): {username}") messages = [] if metadata: messages.append({ - "role": "system", - "content": system_prompt.format( - location=metadata.get("location", "unknown"), - timestamp=metadata.get("timestamp", "unknown"), - username=metadata.get("username", "unknown"), - ), + "role": + "system", + "content": + system_prompt.format( + location=metadata.get("location", "unknown"), + timestamp=metadata.get("timestamp", "unknown"), + username=metadata.get("username", "unknown"), + ), }) tool_call_id_counter = 123456789 @@ -69,8 +69,10 @@ def _build_messages(conversation_history: list[dict], metadata: dict | None = No elif turn["role"] == "api": tool_call_id = str(tool_call_id_counter) messages.append({ - "role": "assistant", - "content": "", + "role": + "assistant", + "content": + "", "tool_calls": [{ "id": tool_call_id, "type": "function", @@ -95,9 +97,13 @@ def _build_messages(conversation_history: list[dict], metadata: dict | None = No @register_function(config_type=ToolTalkWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def tooltalk_workflow(config: ToolTalkWorkflowConfig, builder: Builder): - from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage - - from tooltalk.apis import ALL_APIS, APIS_BY_NAME, SUITES_BY_NAME + from langchain_core.messages import AIMessage + from langchain_core.messages import HumanMessage + from langchain_core.messages import SystemMessage + from langchain_core.messages import ToolMessage + from tooltalk.apis import ALL_APIS + from tooltalk.apis import APIS_BY_NAME + from tooltalk.apis import SUITES_BY_NAME from tooltalk.evaluation.tool_executor import ToolExecutor llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) @@ -112,11 +118,7 @@ async def _run_conversation(input_json: str) -> str: if config.api_mode == "exact": apis_used = [APIS_BY_NAME[name] for name in conversation["apis_used"]] elif config.api_mode == "suite": - apis_used = [ - api - for suite_name in conversation["suites_used"] - for api in SUITES_BY_NAME[suite_name].apis - ] + apis_used = [api for suite_name in conversation["suites_used"] for api in SUITES_BY_NAME[suite_name].apis] else: apis_used = ALL_APIS @@ -159,14 +161,15 @@ async def _run_conversation(input_json: str) -> str: lc_messages.append(HumanMessage(content=msg["content"])) elif msg["role"] == "assistant": if "tool_calls" in msg and msg["tool_calls"]: - lc_messages.append(AIMessage( - content=msg.get("content", ""), - tool_calls=[{ - "name": tc["function"]["name"], - "args": json.loads(tc["function"]["arguments"]), - "id": tc["id"], - } for tc in msg["tool_calls"]], - )) + lc_messages.append( + AIMessage( + content=msg.get("content", ""), + tool_calls=[{ + "name": tc["function"]["name"], + "args": json.loads(tc["function"]["arguments"]), + "id": tc["id"], + } for tc in msg["tool_calls"]], + )) else: lc_messages.append(AIMessage(content=msg["content"])) elif msg["role"] == "tool": diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py index 2d69d1bf66..ac964f923c 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_dataset.py @@ -15,23 +15,39 @@ """Tests for Agent Leaderboard dataset loader — no network required for unit tests.""" import json -import os -import pandas as pd import pytest -from nat.plugins.benchmarks.agent_leaderboard.dataset import ( - load_agent_leaderboard_dataset, - _derive_expected_tool_calls, -) +from nat.plugins.benchmarks.agent_leaderboard.dataset import _derive_expected_tool_calls +from nat.plugins.benchmarks.agent_leaderboard.dataset import load_agent_leaderboard_dataset def _make_sample_tools(): return [ - {"title": "get_account_balance", "description": "Get the balance of an account", "properties": {}, "required": []}, - {"title": "transfer_funds", "description": "Transfer money between accounts", "properties": {}, "required": []}, - {"title": "get_exchange_rates", "description": "Get currency exchange rates", "properties": {}, "required": []}, - {"title": "schedule_appointment", "description": "Schedule a branch appointment", "properties": {}, "required": []}, + { + "title": "get_account_balance", + "description": "Get the balance of an account", + "properties": {}, + "required": [] + }, + { + "title": "transfer_funds", + "description": "Transfer money between accounts", + "properties": {}, + "required": [] + }, + { + "title": "get_exchange_rates", + "description": "Get currency exchange rates", + "properties": {}, + "required": [] + }, + { + "title": "schedule_appointment", + "description": "Schedule a branch appointment", + "properties": {}, + "required": [] + }, ] @@ -44,10 +60,16 @@ def _make_sample_entry(idx: int = 0, domain: str = "banking"): "user_goals": ["Check account balance", "Transfer funds"], "available_tools": tools, "expected_tool_calls": [ - {"tool": "get_account_balance", "parameters": {}}, - {"tool": "transfer_funds", "parameters": {}}, + { + "tool": "get_account_balance", "parameters": {} + }, + { + "tool": "transfer_funds", "parameters": {} + }, ], - "metadata": {"domain": domain, "persona_name": "Test User", "num_goals": 2}, + "metadata": { + "domain": domain, "persona_name": "Test User", "num_goals": 2 + }, } @@ -78,9 +100,7 @@ def test_no_match_returns_empty(self): def test_deduplicates(self): tools = _make_sample_tools() - expected = _derive_expected_tool_calls( - ["Check balance", "Also check my balance again"], tools - ) + expected = _derive_expected_tool_calls(["Check balance", "Also check my balance again"], tools) tool_names = [tc["tool"] for tc in expected] assert tool_names.count("get_account_balance") == 1 @@ -138,7 +158,7 @@ class TestHuggingFaceDownload: def test_downloads_banking_domain(self): """Downloads real data from HuggingFace — requires network.""" try: - from datasets import load_dataset + import datasets # noqa: F401 except ImportError: pytest.skip("datasets not installed") diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py index 681655853a..7c4f09b9a1 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator.py @@ -16,10 +16,9 @@ import json -import pytest - from nat.data_models.evaluator import EvalInputItem -from nat.plugins.benchmarks.agent_leaderboard.evaluator import _evaluate_single, _normalize_tool_name +from nat.plugins.benchmarks.agent_leaderboard.evaluator import _evaluate_single +from nat.plugins.benchmarks.agent_leaderboard.evaluator import _normalize_tool_name def _make_entry(expected_tools: list[str], predicted_tools: list[str]) -> tuple[EvalInputItem, list]: @@ -129,8 +128,11 @@ def test_none_output(self): """None output → score 0.""" entry = {"expected_tool_calls": [{"tool": "t", "parameters": {}}]} item = EvalInputItem( - id="test", input_obj="{}", expected_output_obj="[]", - output_obj=None, full_dataset_entry=entry, + id="test", + input_obj="{}", + expected_output_obj="[]", + output_obj=None, + full_dataset_entry=entry, ) result = _evaluate_single(item, 1.0, 0.0) assert result.score == 0.0 @@ -151,9 +153,12 @@ def test_handles_full_entry_as_string(self): """full_dataset_entry can be a JSON string.""" entry = {"expected_tool_calls": [{"tool": "get_balance", "parameters": {}}]} item = EvalInputItem( - id="test", input_obj="{}", + id="test", + input_obj="{}", expected_output_obj="[]", - output_obj=json.dumps([{"tool": "get_balance", "parameters": {}}]), + output_obj=json.dumps([{ + "tool": "get_balance", "parameters": {} + }]), full_dataset_entry=json.dumps(entry), ) result = _evaluate_single(item, 1.0, 0.0) diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py index a345dece47..1d49a69ec8 100644 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py +++ b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/test_evaluator_comprehensive.py @@ -114,8 +114,11 @@ class TestEdgeCases: def test_malformed_json_output(self): entry = {"expected_tool_calls": [{"tool": "t", "parameters": {}}]} item = EvalInputItem( - id="bad", input_obj="{}", expected_output_obj="[]", - output_obj="not json", full_dataset_entry=entry, + id="bad", + input_obj="{}", + expected_output_obj="[]", + output_obj="not json", + full_dataset_entry=entry, ) result = _evaluate_single(item, 1.0, 0.0) assert result.score == 0.0 @@ -123,8 +126,11 @@ def test_malformed_json_output(self): def test_output_is_dict_not_list(self): entry = {"expected_tool_calls": [{"tool": "t", "parameters": {}}]} item = EvalInputItem( - id="bad", input_obj="{}", expected_output_obj="[]", - output_obj='{"tool": "t"}', full_dataset_entry=entry, + id="bad", + input_obj="{}", + expected_output_obj="[]", + output_obj='{"tool": "t"}', + full_dataset_entry=entry, ) result = _evaluate_single(item, 1.0, 0.0) # dict is not a list → predicted = [] → score 0 diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py index 4cfaaf8b74..2ac737b13b 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_dataset.py @@ -17,7 +17,6 @@ import json import os -import pandas as pd import pytest from nat.plugins.benchmarks.bfcl.dataset import load_bfcl_dataset @@ -25,14 +24,21 @@ def _make_bfcl_entry(entry_id: str, question: str = "Calculate area", func_name: str = "calc") -> dict: return { - "id": entry_id, - "question": [[{"role": "user", "content": question}]], + "id": + entry_id, + "question": [[{ + "role": "user", "content": question + }]], "function": [{ "name": func_name, "description": "A test function", "parameters": { "type": "dict", - "properties": {"x": {"type": "integer", "description": "value"}}, + "properties": { + "x": { + "type": "integer", "description": "value" + } + }, "required": ["x"], }, }], @@ -42,7 +48,11 @@ def _make_bfcl_entry(entry_id: str, question: str = "Calculate area", func_name: def _make_bfcl_answer(entry_id: str) -> dict: return { "id": entry_id, - "ground_truth": [{"calc": {"x": [10]}}], + "ground_truth": [{ + "calc": { + "x": [10] + } + }], } diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py index 62cdab2c63..266d50af59 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator.py @@ -18,18 +18,14 @@ correctly through the evaluator. """ +import importlib.util import json -import os import pytest from nat.data_models.evaluator import EvalInputItem -try: - from bfcl.eval_checker.ast_eval.ast_checker import ast_checker - _HAS_BFCL = True -except ImportError: - _HAS_BFCL = False +_HAS_BFCL = importlib.util.find_spec("bfcl.eval_checker") is not None pytestmark = pytest.mark.skipif(not _HAS_BFCL, reason="bfcl not installed") @@ -37,17 +33,26 @@ def _make_simple_entry() -> dict: """BFCL simple test: calculate_triangle_area(base=10, height=5).""" return { - "id": "simple_0", - "question": [[{"role": "user", "content": "Find area of triangle with base 10, height 5"}]], + "id": + "simple_0", + "question": [[{ + "role": "user", "content": "Find area of triangle with base 10, height 5" + }]], "function": [{ "name": "calculate_triangle_area", "description": "Calculate the area of a triangle.", "parameters": { "type": "dict", "properties": { - "base": {"type": "integer", "description": "The base"}, - "height": {"type": "integer", "description": "The height"}, - "unit": {"type": "string", "description": "Unit of measure"}, + "base": { + "type": "integer", "description": "The base" + }, + "height": { + "type": "integer", "description": "The height" + }, + "unit": { + "type": "string", "description": "Unit of measure" + }, }, "required": ["base", "height"], }, diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py index af008b1f97..3e361b326f 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_evaluator_comprehensive.py @@ -14,45 +14,51 @@ # limitations under the License. """Comprehensive evaluator tests covering all BFCL scoring paths.""" +import importlib.util import json import pytest -try: - from bfcl.eval_checker.ast_eval.ast_checker import ast_checker - _HAS_BFCL = True -except ImportError: - _HAS_BFCL = False +_HAS_BFCL = importlib.util.find_spec("bfcl.eval_checker") is not None pytestmark = pytest.mark.skipif(not _HAS_BFCL, reason="bfcl not installed") -from nat.data_models.evaluator import EvalInputItem -from nat.plugins.benchmarks.bfcl.evaluator import ( - _evaluate_single, - _extract_function_call, - _try_convert_json_to_call, - _extract_calls_from_code, -) +from nat.data_models.evaluator import EvalInputItem # noqa: E402 +from nat.plugins.benchmarks.bfcl.evaluator import _evaluate_single # noqa: E402 +from nat.plugins.benchmarks.bfcl.evaluator import _extract_calls_from_code # noqa: E402 +from nat.plugins.benchmarks.bfcl.evaluator import _extract_function_call # noqa: E402 +from nat.plugins.benchmarks.bfcl.evaluator import _try_convert_json_to_call # noqa: E402 def _make_item(entry, answer, output): return EvalInputItem( - id=entry["id"], input_obj=json.dumps(entry), + id=entry["id"], + input_obj=json.dumps(entry), expected_output_obj=json.dumps(answer), - output_obj=output, full_dataset_entry=entry, + output_obj=output, + full_dataset_entry=entry, ) def _simple_entry(): return { - "id": "simple_0", - "question": [[{"role": "user", "content": "Calculate area"}]], + "id": + "simple_0", + "question": [[{ + "role": "user", "content": "Calculate area" + }]], "function": [{ "name": "calc_area", "description": "Calculate area", "parameters": { "type": "dict", - "properties": {"base": {"type": "integer"}, "height": {"type": "integer"}}, + "properties": { + "base": { + "type": "integer" + }, "height": { + "type": "integer" + } + }, "required": ["base", "height"], }, }], @@ -112,19 +118,50 @@ class TestParallelCategory: def test_parallel_calls_scored(self): entry = { - "id": "parallel_0", - "question": [[{"role": "user", "content": "Get area and perimeter"}]], + "id": + "parallel_0", + "question": [[{ + "role": "user", "content": "Get area and perimeter" + }]], "function": [ - {"name": "calc_area", "description": "Area", "parameters": { - "type": "dict", "properties": {"x": {"type": "integer"}}, "required": ["x"]}}, - {"name": "calc_perimeter", "description": "Perimeter", "parameters": { - "type": "dict", "properties": {"x": {"type": "integer"}}, "required": ["x"]}}, + { + "name": "calc_area", + "description": "Area", + "parameters": { + "type": "dict", "properties": { + "x": { + "type": "integer" + } + }, "required": ["x"] + } + }, + { + "name": "calc_perimeter", + "description": "Perimeter", + "parameters": { + "type": "dict", "properties": { + "x": { + "type": "integer" + } + }, "required": ["x"] + } + }, ], } - answer = {"id": "parallel_0", "ground_truth": [ - {"calc_area": {"x": [5]}}, - {"calc_perimeter": {"x": [5]}}, - ]} + answer = { + "id": "parallel_0", "ground_truth": [ + { + "calc_area": { + "x": [5] + } + }, + { + "calc_perimeter": { + "x": [5] + } + }, + ] + } item = _make_item(entry, answer, "[calc_area(x=5), calc_perimeter(x=5)]") result = _evaluate_single(item, "parallel", "Python") assert result.score == 1.0 diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py index b97cf44437..b451d7b16b 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_integration.py @@ -27,7 +27,8 @@ _SKIP_REASON = None try: - from bfcl.constant import PROMPT_PATH, POSSIBLE_ANSWER_PATH + from bfcl.constant import POSSIBLE_ANSWER_PATH + from bfcl.constant import PROMPT_PATH _SIMPLE_FILE = os.path.join(PROMPT_PATH, "BFCL_v3_simple.json") if not os.path.isfile(_SIMPLE_FILE): _SKIP_REASON = "BFCL_v3_simple.json not found" @@ -107,7 +108,9 @@ async def test_end_to_end_bfcl_ast_eval(self, small_bfcl_dataset, tmp_path): "_type": "bfcl", "file_path": small_bfcl_dataset, "test_category": "simple", - "structure": {"question_key": "question", "answer_key": "answer"}, + "structure": { + "question_key": "question", "answer_key": "answer" + }, }, }, "evaluators": { @@ -125,8 +128,13 @@ async def test_end_to_end_bfcl_ast_eval(self, small_bfcl_dataset, tmp_path): result = subprocess.run( ["nat", "eval", "--config_file", str(config_path)], - capture_output=True, text=True, timeout=240, - env={**os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"]}, + capture_output=True, + text=True, + timeout=240, + check=False, + env={ + **os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"] + }, ) assert result.returncode == 0, f"nat eval failed:\n{result.stderr[-2000:]}" @@ -176,7 +184,9 @@ async def test_end_to_end_bfcl_react_eval(self, small_bfcl_dataset, tmp_path): "_type": "bfcl", "file_path": small_bfcl_dataset, "test_category": "simple", - "structure": {"question_key": "question", "answer_key": "answer"}, + "structure": { + "question_key": "question", "answer_key": "answer" + }, }, }, "evaluators": { @@ -194,8 +204,13 @@ async def test_end_to_end_bfcl_react_eval(self, small_bfcl_dataset, tmp_path): result = subprocess.run( ["nat", "eval", "--config_file", str(config_path)], - capture_output=True, text=True, timeout=240, - env={**os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"]}, + capture_output=True, + text=True, + timeout=240, + check=False, + env={ + **os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"] + }, ) assert result.returncode == 0, f"nat eval failed:\n{result.stderr[-2000:]}" diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py index f8c31f65f4..f8acc54986 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_regression.py @@ -14,8 +14,6 @@ # limitations under the License. """Regression tests for BFCL evaluator — pinned behavior for known outputs.""" -import pytest - from nat.plugins.benchmarks.bfcl.evaluator import _extract_function_call diff --git a/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py index 59fd9f3c59..1b449278e6 100644 --- a/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py +++ b/packages/nvidia_nat_benchmarks/tests/bfcl/test_tool_intent_stubs.py @@ -20,18 +20,16 @@ import pytest -from nat.plugins.benchmarks.bfcl.tool_intent_stubs import ( - ToolIntentBuffer, - PermissiveToolInput, - _GLOBAL_INTENT_REGISTRY, - _current_scenario_id, - _generate_mock_response, - clear_global_intents, - create_tool_stub_function, - get_current_scenario_id, - get_global_intents, - set_current_scenario_id, -) +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import _GLOBAL_INTENT_REGISTRY +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import PermissiveToolInput +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import ToolIntentBuffer +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import _current_scenario_id +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import _generate_mock_response +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import clear_global_intents +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import create_tool_stub_function +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import get_current_scenario_id +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import get_global_intents +from nat.plugins.benchmarks.bfcl.tool_intent_stubs import set_current_scenario_id @pytest.fixture(autouse=True) diff --git a/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py b/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py index b9e1b6a5f6..51ddb64898 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/fixtures/sample_benchmark.py @@ -13,18 +13,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -from nemo_evaluator.contrib.byob import ScorerInput, benchmark, scorer -from nemo_evaluator.contrib.byob.scorers import exact_match - import json import os import tempfile +from nemo_evaluator.contrib.byob import ScorerInput +from nemo_evaluator.contrib.byob import benchmark +from nemo_evaluator.contrib.byob import scorer +from nemo_evaluator.contrib.byob.scorers import exact_match + # Create a tiny test dataset as a temp file _DATA = [ - {"id": "0", "question": "What is 2+2?", "target": "4"}, - {"id": "1", "question": "What color is the sky?", "target": "blue"}, - {"id": "2", "question": "Capital of France?", "target": "Paris"}, + { + "id": "0", "question": "What is 2+2?", "target": "4" + }, + { + "id": "1", "question": "What color is the sky?", "target": "blue" + }, + { + "id": "2", "question": "Capital of France?", "target": "Paris" + }, ] _DATASET_PATH = os.path.join(tempfile.gettempdir(), "byob_test_dataset.jsonl") diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py index d8379cd3f7..1c2ce1ff5e 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator.py @@ -14,23 +14,22 @@ # limitations under the License. """Tests for the BYOB evaluator — no LLM required.""" -import json import os -import sys import pytest try: from nemo_evaluator.contrib.byob.decorators import ScorerInput - from nemo_evaluator.contrib.byob.scorers import exact_match, contains, f1_token + from nemo_evaluator.contrib.byob.scorers import contains + from nemo_evaluator.contrib.byob.scorers import exact_match + from nemo_evaluator.contrib.byob.scorers import f1_token _HAS_BYOB = True except ImportError: _HAS_BYOB = False pytestmark = pytest.mark.skipif(not _HAS_BYOB, reason="nemo_evaluator BYOB not installed") - -from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalInputItem # noqa: E402 class TestBYOBEvaluator: @@ -40,9 +39,13 @@ def test_exact_match_correct(self): from nat.plugins.benchmarks.byob.evaluator import _evaluate_single item = EvalInputItem( - id="0", input_obj='{"question": "2+2?"}', - expected_output_obj="4", output_obj="4", - full_dataset_entry={"question": "2+2?", "target": "4"}, + id="0", + input_obj='{"question": "2+2?"}', + expected_output_obj="4", + output_obj="4", + full_dataset_entry={ + "question": "2+2?", "target": "4" + }, ) result = _evaluate_single(item, exact_match, "target", "correct", {}) @@ -54,9 +57,13 @@ def test_exact_match_wrong(self): from nat.plugins.benchmarks.byob.evaluator import _evaluate_single item = EvalInputItem( - id="1", input_obj='{"question": "2+2?"}', - expected_output_obj="4", output_obj="5", - full_dataset_entry={"question": "2+2?", "target": "4"}, + id="1", + input_obj='{"question": "2+2?"}', + expected_output_obj="4", + output_obj="5", + full_dataset_entry={ + "question": "2+2?", "target": "4" + }, ) result = _evaluate_single(item, exact_match, "target", "correct", {}) @@ -68,8 +75,10 @@ def test_contains_scorer(self): from nat.plugins.benchmarks.byob.evaluator import _evaluate_single item = EvalInputItem( - id="2", input_obj='{}', - expected_output_obj="Paris", output_obj="The capital of France is Paris.", + id="2", + input_obj='{}', + expected_output_obj="Paris", + output_obj="The capital of France is Paris.", full_dataset_entry={"target": "Paris"}, ) result = _evaluate_single(item, contains, "target", "correct", {}) @@ -81,7 +90,8 @@ def test_f1_token_scorer(self): from nat.plugins.benchmarks.byob.evaluator import _evaluate_single item = EvalInputItem( - id="3", input_obj='{}', + id="3", + input_obj='{}', expected_output_obj="the quick brown fox", output_obj="the quick brown dog", full_dataset_entry={"target": "the quick brown fox"}, @@ -96,8 +106,10 @@ def test_none_output_scores_0(self): from nat.plugins.benchmarks.byob.evaluator import _evaluate_single item = EvalInputItem( - id="4", input_obj='{}', - expected_output_obj="answer", output_obj=None, + id="4", + input_obj='{}', + expected_output_obj="answer", + output_obj=None, full_dataset_entry={}, ) result = _evaluate_single(item, exact_match, "target", "correct", {}) @@ -111,9 +123,7 @@ def test_import_sample_benchmark(self): """Can import and use the sample benchmark definition.""" from nemo_evaluator.contrib.byob.eval_logic import import_benchmark - fixture_path = os.path.join( - os.path.dirname(__file__), "fixtures", "sample_benchmark.py" - ) + fixture_path = os.path.join(os.path.dirname(__file__), "fixtures", "sample_benchmark.py") bench = import_benchmark(fixture_path, "test_exact_match") assert bench.name == "test-exact-match" @@ -122,7 +132,9 @@ def test_import_sample_benchmark(self): # Test the scorer scorer_input = ScorerInput( - response="4", target="4", metadata={}, + response="4", + target="4", + metadata={}, ) result = bench.scorer_fn(scorer_input) assert result["correct"] is True @@ -131,9 +143,7 @@ def test_import_and_load_dataset(self): """Can load dataset from sample benchmark.""" from nat.plugins.benchmarks.byob.dataset import load_byob_dataset - fixture_path = os.path.join( - os.path.dirname(__file__), "fixtures", "sample_benchmark.py" - ) + fixture_path = os.path.join(os.path.dirname(__file__), "fixtures", "sample_benchmark.py") df = load_byob_dataset( file_path="ignored", benchmark_module=fixture_path, diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py index 9e0a8f0a13..a0c4cca52c 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_evaluator_comprehensive.py @@ -20,15 +20,16 @@ try: from nemo_evaluator.contrib.byob.decorators import ScorerInput - from nemo_evaluator.contrib.byob.scorers import exact_match, contains, f1_token + from nemo_evaluator.contrib.byob.scorers import exact_match + from nemo_evaluator.contrib.byob.scorers import f1_token _HAS_BYOB = True except ImportError: _HAS_BYOB = False pytestmark = pytest.mark.skipif(not _HAS_BYOB, reason="nemo_evaluator BYOB not installed") -from nat.data_models.evaluator import EvalInputItem -from nat.plugins.benchmarks.byob.evaluator import _evaluate_single +from nat.data_models.evaluator import EvalInputItem # noqa: E402 +from nat.plugins.benchmarks.byob.evaluator import _evaluate_single # noqa: E402 class TestScoreFieldSelection: @@ -36,15 +37,20 @@ class TestScoreFieldSelection: def test_default_correct_field(self): item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="hello", - output_obj="hello", full_dataset_entry={"target": "hello"}, + id="0", + input_obj="{}", + expected_output_obj="hello", + output_obj="hello", + full_dataset_entry={"target": "hello"}, ) result = _evaluate_single(item, exact_match, "target", "correct", {}) assert result.score == 1.0 def test_f1_score_field(self): item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="the quick brown fox", + id="0", + input_obj="{}", + expected_output_obj="the quick brown fox", output_obj="the quick brown dog", full_dataset_entry={"target": "the quick brown fox"}, ) @@ -56,7 +62,9 @@ def test_f1_score_field(self): def test_precision_score_field(self): item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="a b c", + id="0", + input_obj="{}", + expected_output_obj="a b c", output_obj="a b c d e", full_dataset_entry={"target": "a b c"}, ) @@ -66,16 +74,22 @@ def test_precision_score_field(self): def test_missing_score_field_returns_0(self): item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="hello", - output_obj="hello", full_dataset_entry={"target": "hello"}, + id="0", + input_obj="{}", + expected_output_obj="hello", + output_obj="hello", + full_dataset_entry={"target": "hello"}, ) result = _evaluate_single(item, exact_match, "target", "nonexistent_field", {}) assert result.score == 0.0 def test_boolean_score_converted_to_float(self): item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="yes", - output_obj="yes", full_dataset_entry={"target": "yes"}, + id="0", + input_obj="{}", + expected_output_obj="yes", + output_obj="yes", + full_dataset_entry={"target": "yes"}, ) result = _evaluate_single(item, exact_match, "target", "correct", {}) assert isinstance(result.score, float) @@ -87,14 +101,19 @@ class TestMetadataPassthrough: def test_metadata_available_to_scorer(self): """Custom scorer that reads metadata.""" + def metadata_checker(sample: ScorerInput) -> dict: has_extra = "extra_field" in sample.metadata return {"correct": has_extra} item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="x", + id="0", + input_obj="{}", + expected_output_obj="x", output_obj="x", - full_dataset_entry={"target": "x", "extra_field": "present"}, + full_dataset_entry={ + "target": "x", "extra_field": "present" + }, ) result = _evaluate_single(item, metadata_checker, "target", "correct", {}) assert result.score == 1.0 @@ -102,9 +121,13 @@ def metadata_checker(sample: ScorerInput) -> dict: def test_string_full_entry_parsed_to_dict(self): """full_dataset_entry as JSON string should be parsed.""" item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="hello", + id="0", + input_obj="{}", + expected_output_obj="hello", output_obj="hello", - full_dataset_entry=json.dumps({"target": "hello", "category": "test"}), + full_dataset_entry=json.dumps({ + "target": "hello", "category": "test" + }), ) result = _evaluate_single(item, exact_match, "target", "correct", {}) assert result.score == 1.0 @@ -114,12 +137,15 @@ class TestExtraConfig: """Verify extra_config is passed to the scorer.""" def test_config_available_to_scorer(self): + def config_scorer(sample: ScorerInput) -> dict: threshold = sample.config.get("threshold", 0.5) return {"correct": len(sample.response) > threshold} item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="x", + id="0", + input_obj="{}", + expected_output_obj="x", output_obj="hello world", full_dataset_entry={"target": "x"}, ) @@ -131,12 +157,16 @@ class TestScorerErrors: """Verify error handling when the scorer raises exceptions.""" def test_scorer_exception_returns_0(self): + def bad_scorer(sample: ScorerInput) -> dict: raise ValueError("Scorer crashed!") item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="x", - output_obj="hello", full_dataset_entry={"target": "x"}, + id="0", + input_obj="{}", + expected_output_obj="x", + output_obj="hello", + full_dataset_entry={"target": "x"}, ) result = _evaluate_single(item, bad_scorer, "target", "correct", {}) assert result.score == 0.0 @@ -148,20 +178,27 @@ class TestTargetParsing: def test_string_target(self): item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj="Paris", - output_obj="Paris", full_dataset_entry={"target": "Paris"}, + id="0", + input_obj="{}", + expected_output_obj="Paris", + output_obj="Paris", + full_dataset_entry={"target": "Paris"}, ) result = _evaluate_single(item, exact_match, "target", "correct", {}) assert result.score == 1.0 def test_json_target_parsed(self): """JSON-encoded target should be parsed.""" + def list_scorer(sample: ScorerInput) -> dict: return {"correct": isinstance(sample.target, list)} item = EvalInputItem( - id="0", input_obj="{}", expected_output_obj='["a", "b"]', - output_obj="x", full_dataset_entry={"target": ["a", "b"]}, + id="0", + input_obj="{}", + expected_output_obj='["a", "b"]', + output_obj="x", + full_dataset_entry={"target": ["a", "b"]}, ) result = _evaluate_single(item, list_scorer, "target", "correct", {}) assert result.score == 1.0 diff --git a/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py b/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py index bf04404b16..61c388e1d3 100644 --- a/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py +++ b/packages/nvidia_nat_benchmarks/tests/byob/test_integration.py @@ -25,7 +25,6 @@ import pytest try: - from nemo_evaluator.contrib.byob.decorators import ScorerInput from nemo_evaluator.contrib.byob.eval_logic import import_benchmark _HAS_BYOB = True except ImportError: @@ -33,49 +32,62 @@ pytestmark = pytest.mark.skipif(not _HAS_BYOB, reason="nemo_evaluator BYOB not installed") -from nat.data_models.evaluator import EvalInput, EvalInputItem -from nat.plugins.benchmarks.byob.evaluator import _evaluate_single +from nat.data_models.evaluator import EvalInputItem # noqa: E402 +from nat.plugins.benchmarks.byob.evaluator import _evaluate_single # noqa: E402 class TestBYOBIntegration: def test_byob_scorer_pipeline_exact_match(self): """Full pipeline: import benchmark → create items → score with exact_match.""" - fixture_path = os.path.join( - os.path.dirname(__file__), "fixtures", "sample_benchmark.py" - ) + fixture_path = os.path.join(os.path.dirname(__file__), "fixtures", "sample_benchmark.py") bench = import_benchmark(fixture_path, "test_exact_match") # Simulate items that the eval runner would create items = [ EvalInputItem( id="0", - input_obj=json.dumps({"question": "What is 2+2?", "target": "4"}), + input_obj=json.dumps({ + "question": "What is 2+2?", "target": "4" + }), expected_output_obj="4", output_obj="4", # Correct answer - full_dataset_entry={"question": "What is 2+2?", "target": "4"}, + full_dataset_entry={ + "question": "What is 2+2?", "target": "4" + }, ), EvalInputItem( id="1", - input_obj=json.dumps({"question": "Sky color?", "target": "blue"}), + input_obj=json.dumps({ + "question": "Sky color?", "target": "blue" + }), expected_output_obj="blue", output_obj="red", # Wrong answer - full_dataset_entry={"question": "Sky color?", "target": "blue"}, + full_dataset_entry={ + "question": "Sky color?", "target": "blue" + }, ), EvalInputItem( id="2", - input_obj=json.dumps({"question": "Capital of France?", "target": "Paris"}), + input_obj=json.dumps({ + "question": "Capital of France?", "target": "Paris" + }), expected_output_obj="Paris", output_obj="Paris", # Correct answer - full_dataset_entry={"question": "Capital of France?", "target": "Paris"}, + full_dataset_entry={ + "question": "Capital of France?", "target": "Paris" + }, ), ] results = [] for item in items: result = _evaluate_single( - item, bench.scorer_fn, bench.target_field, - "correct", bench.extra_config, + item, + bench.scorer_fn, + bench.target_field, + "correct", + bench.extra_config, ) results.append(result) @@ -91,9 +103,7 @@ def test_byob_dataset_to_evaluator_roundtrip(self): """Full roundtrip: load dataset → create items → score.""" from nat.plugins.benchmarks.byob.dataset import load_byob_dataset - fixture_path = os.path.join( - os.path.dirname(__file__), "fixtures", "sample_benchmark.py" - ) + fixture_path = os.path.join(os.path.dirname(__file__), "fixtures", "sample_benchmark.py") # Load dataset df = load_byob_dataset("ignored", benchmark_module=fixture_path, benchmark_name="test_exact_match") @@ -105,20 +115,24 @@ def test_byob_dataset_to_evaluator_roundtrip(self): # Create eval items from DataFrame (simulating what DatasetHandler does) items = [] for _, row in df.iterrows(): - items.append(EvalInputItem( - id=row["id"], - input_obj=row["question"], - expected_output_obj=row["answer"], - output_obj=row["answer"], # Simulate perfect answers - full_dataset_entry=json.loads(row["question"]), - )) + items.append( + EvalInputItem( + id=row["id"], + input_obj=row["question"], + expected_output_obj=row["answer"], + output_obj=row["answer"], # Simulate perfect answers + full_dataset_entry=json.loads(row["question"]), + )) # Score all items results = [] for item in items: result = _evaluate_single( - item, bench.scorer_fn, bench.target_field, - "correct", bench.extra_config, + item, + bench.scorer_fn, + bench.target_field, + "correct", + bench.extra_config, ) results.append(result) diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py index a3ccce69c3..c334b2220b 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/conftest.py @@ -20,7 +20,6 @@ """ import sys -import types from unittest.mock import MagicMock diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py index dfb1306b09..d97c3f6937 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_dataset.py @@ -16,7 +16,6 @@ import json import os -import tempfile import pandas as pd import pytest @@ -27,12 +26,17 @@ def _make_conversation(conversation_id: str, user_text: str = "Hello") -> dict: """Create a minimal ToolTalk conversation for testing.""" return { - "name": f"test-{conversation_id}", - "conversation_id": conversation_id, + "name": + f"test-{conversation_id}", + "conversation_id": + conversation_id, "suites_used": ["Alarm"], "apis_used": ["AddAlarm"], - "scenario": "test scenario", - "user": {"username": "testuser", "session_token": "abc-123"}, + "scenario": + "test scenario", + "user": { + "username": "testuser", "session_token": "abc-123" + }, "metadata": { "location": "New York", "timestamp": "2023-09-11 13:00:00", @@ -40,14 +44,25 @@ def _make_conversation(conversation_id: str, user_text: str = "Hello") -> dict: "username": "testuser", }, "conversation": [ - {"index": 0, "role": "user", "text": user_text}, { - "index": 1, - "role": "assistant", - "text": "Done.", + "index": 0, "role": "user", "text": user_text + }, + { + "index": + 1, + "role": + "assistant", + "text": + "Done.", "apis": [{ - "request": {"api_name": "AddAlarm", "parameters": {"time": "18:30:00"}}, - "response": {"alarm_id": "1234-5678"}, + "request": { + "api_name": "AddAlarm", "parameters": { + "time": "18:30:00" + } + }, + "response": { + "alarm_id": "1234-5678" + }, "exception": None, }], }, diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py index b56c8c9aad..3d0257fa8f 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator.py @@ -57,18 +57,26 @@ def _make_conversation_with_predictions(predictions_match_ground_truth: bool) -> correct_api_call = { "request": { "api_name": "AddAlarm", - "parameters": {"session_token": "98a5a87a-7714-b404", "time": "18:30:00"}, + "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "18:30:00" + }, + }, + "response": { + "alarm_id": "5bff-dd80" }, - "response": {"alarm_id": "5bff-dd80"}, "exception": None, } wrong_api_call = { "request": { "api_name": "AddAlarm", - "parameters": {"session_token": "98a5a87a-7714-b404", "time": "19:00:00"}, + "parameters": { + "session_token": "98a5a87a-7714-b404", "time": "19:00:00" + }, + }, + "response": { + "alarm_id": "aaaa-bbbb" }, - "response": {"alarm_id": "aaaa-bbbb"}, "exception": None, } @@ -78,11 +86,14 @@ def _make_conversation_with_predictions(predictions_match_ground_truth: bool) -> prediction_api["bad_action"] = False return { - "name": "test-conversation", - "conversation_id": "test-001", + "name": + "test-conversation", + "conversation_id": + "test-001", "suites_used": ["Alarm"], "apis_used": ["AddAlarm"], - "scenario": "test", + "scenario": + "test", "user": { "username": "justinkool", "email": "test@test.com", @@ -98,7 +109,9 @@ def _make_conversation_with_predictions(predictions_match_ground_truth: bool) -> "username": "justinkool", }, "conversation": [ - {"index": 0, "role": "user", "text": "Set an alarm for 6:30 PM"}, + { + "index": 0, "role": "user", "text": "Set an alarm for 6:30 PM" + }, { "index": 1, "role": "assistant", @@ -106,7 +119,9 @@ def _make_conversation_with_predictions(predictions_match_ground_truth: bool) -> "apis": [correct_api_call], "predictions": [ prediction_api, - {"role": "assistant", "text": "Alarm set."}, + { + "role": "assistant", "text": "Alarm set." + }, ], }, ], diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py index 0b56a5b486..a412ae24b5 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_evaluator_comprehensive.py @@ -30,35 +30,63 @@ pytestmark = pytest.mark.skipif(not _HAS_TOOLTALK, reason="tooltalk not installed") -from nat.plugins.benchmarks.tooltalk.evaluator import _evaluate_single +from nat.plugins.benchmarks.tooltalk.evaluator import _evaluate_single # noqa: E402 def _alarm_conv(predictions): """Build a standard AddAlarm conversation with given predictions.""" return { - "name": "test", "conversation_id": "test-001", - "suites_used": ["Alarm"], "apis_used": ["AddAlarm"], - "scenario": "test", - "user": {"username": "testuser", "email": "t@t.com", "phone": "123-456-7890", - "name": "Test", "password": "pass", "session_token": "tok-123"}, - "metadata": {"location": "NY", "timestamp": "2023-09-11 13:00:00", - "session_token": "tok-123", "username": "testuser"}, + "name": + "test", + "conversation_id": + "test-001", + "suites_used": ["Alarm"], + "apis_used": ["AddAlarm"], + "scenario": + "test", + "user": { + "username": "testuser", + "email": "t@t.com", + "phone": "123-456-7890", + "name": "Test", + "password": "pass", + "session_token": "tok-123" + }, + "metadata": { + "location": "NY", "timestamp": "2023-09-11 13:00:00", "session_token": "tok-123", "username": "testuser" + }, "conversation": [ - {"index": 0, "role": "user", "text": "Set alarm for 6:30"}, - {"index": 1, "role": "assistant", "text": "Done.", - "apis": [{"request": {"api_name": "AddAlarm", - "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, - "response": {"alarm_id": "5bff-dd80"}, "exception": None}], - "predictions": predictions}, + { + "index": 0, "role": "user", "text": "Set alarm for 6:30" + }, + { + "index": 1, + "role": "assistant", + "text": "Done.", + "apis": [{ + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "tok-123", "time": "18:30:00" + } + }, + "response": { + "alarm_id": "5bff-dd80" + }, + "exception": None + }], + "predictions": predictions + }, ], } def _make_item(conv): return EvalInputItem( - id="test-001", input_obj=json.dumps(conv), + id="test-001", + input_obj=json.dumps(conv), expected_output_obj=json.dumps(conv), - output_obj=json.dumps(conv), full_dataset_entry=conv, + output_obj=json.dumps(conv), + full_dataset_entry=conv, ) @@ -67,10 +95,21 @@ class TestAllMetricFields: def test_perfect_match_all_fields(self): preds = [ - {"role": "api", "request": {"api_name": "AddAlarm", - "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, - "response": {"alarm_id": "5bff-dd80"}, "exception": None}, - {"role": "assistant", "text": "Done."}, + { + "role": "api", + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "tok-123", "time": "18:30:00" + } + }, + "response": { + "alarm_id": "5bff-dd80" + }, + "exception": None + }, + { + "role": "assistant", "text": "Done." + }, ] result = _evaluate_single(_make_item(_alarm_conv(preds)), _DB_DIR) r = result.reasoning @@ -102,16 +141,45 @@ def test_no_api_predictions_all_fields(self): def test_soft_success_calculation(self): """3 predictions: 1 match + 2 bad actions → soft_success = recall*(1-bad_rate).""" preds = [ - {"role": "api", "request": {"api_name": "AddAlarm", - "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, - "response": {"alarm_id": "5bff-dd80"}, "exception": None}, - {"role": "api", "request": {"api_name": "AddAlarm", - "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, - "response": {"alarm_id": "aaaa-bbbb"}, "exception": None}, - {"role": "api", "request": {"api_name": "AddAlarm", - "parameters": {"session_token": "tok-123", "time": "18:30:00"}}, - "response": {"alarm_id": "cccc-dddd"}, "exception": None}, - {"role": "assistant", "text": "Done."}, + { + "role": "api", + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "tok-123", "time": "18:30:00" + } + }, + "response": { + "alarm_id": "5bff-dd80" + }, + "exception": None + }, + { + "role": "api", + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "tok-123", "time": "18:30:00" + } + }, + "response": { + "alarm_id": "aaaa-bbbb" + }, + "exception": None + }, + { + "role": "api", + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "tok-123", "time": "18:30:00" + } + }, + "response": { + "alarm_id": "cccc-dddd" + }, + "exception": None + }, + { + "role": "assistant", "text": "Done." + }, ] result = _evaluate_single(_make_item(_alarm_conv(preds)), _DB_DIR) r = result.reasoning @@ -128,8 +196,11 @@ class TestMalformedInput: def test_invalid_json_output(self): item = EvalInputItem( - id="bad", input_obj="{}", expected_output_obj="{}", - output_obj="not valid json at all", full_dataset_entry={}, + id="bad", + input_obj="{}", + expected_output_obj="{}", + output_obj="not valid json at all", + full_dataset_entry={}, ) result = _evaluate_single(item, _DB_DIR) assert result.score == 0.0 @@ -137,8 +208,11 @@ def test_invalid_json_output(self): def test_empty_string_output(self): item = EvalInputItem( - id="empty", input_obj="{}", expected_output_obj="{}", - output_obj="", full_dataset_entry={}, + id="empty", + input_obj="{}", + expected_output_obj="{}", + output_obj="", + full_dataset_entry={}, ) result = _evaluate_single(item, _DB_DIR) assert result.score == 0.0 diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py index 89e7c9e857..123f4caf5f 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_integration.py @@ -26,7 +26,6 @@ import json import os import shutil -import tempfile import pytest @@ -69,7 +68,6 @@ class TestToolTalkIntegration: async def test_workflow_produces_predictions(self, single_conversation_dir): """The workflow calls a live NIM endpoint and produces tool call predictions.""" from nat.plugins.benchmarks.tooltalk.dataset import load_tooltalk_dataset - from nat.plugins.benchmarks.tooltalk.workflow import _build_tool_schemas, _build_messages # Load dataset df = load_tooltalk_dataset(single_conversation_dir) @@ -91,9 +89,7 @@ async def test_end_to_end_nat_eval(self, single_conversation_dir, tmp_path): "_type": "nim", "model_name": "meta/llama-3.3-70b-instruct", "api_key": os.environ["NVIDIA_API_KEY"], - "base_url": os.environ.get( - "NVIDIA_BASE_URL", "https://integrate.api.nvidia.com/v1" - ), + "base_url": os.environ.get("NVIDIA_BASE_URL", "https://integrate.api.nvidia.com/v1"), "max_tokens": 1024, "temperature": 0.0, }, @@ -142,7 +138,10 @@ async def test_end_to_end_nat_eval(self, single_conversation_dir, tmp_path): capture_output=True, text=True, timeout=240, - env={**os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"]}, + check=False, + env={ + **os.environ, "NVIDIA_API_KEY": os.environ["NVIDIA_API_KEY"] + }, ) # Check that the eval completed @@ -172,6 +171,4 @@ async def test_end_to_end_nat_eval(self, single_conversation_dir, tmp_path): assert "success" in reasoning # recall should be > 0 (the LLM should at least call AddAlarm once correctly) - assert reasoning["recall"] > 0, ( - f"Expected recall > 0 (LLM should call AddAlarm correctly), got {reasoning}" - ) + assert reasoning["recall"] > 0, (f"Expected recall > 0 (LLM should call AddAlarm correctly), got {reasoning}") diff --git a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py index 87fb55297a..7b2d328d04 100644 --- a/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py +++ b/packages/nvidia_nat_benchmarks/tests/tooltalk/test_regression.py @@ -48,11 +48,14 @@ def database_dir(): def _make_alarm_conversation(predictions: list[dict]) -> dict: """Build a ToolTalk AddAlarm conversation with given predictions.""" return { - "name": "regression-test", - "conversation_id": "regression-001", + "name": + "regression-test", + "conversation_id": + "regression-001", "suites_used": ["Alarm"], "apis_used": ["AddAlarm"], - "scenario": "regression", + "scenario": + "regression", "user": { "username": "justinkool", "email": "test@test.com", @@ -68,16 +71,24 @@ def _make_alarm_conversation(predictions: list[dict]) -> dict: "username": "justinkool", }, "conversation": [ - {"index": 0, "role": "user", "text": "Set an alarm for 6:30 PM"}, + { + "index": 0, "role": "user", "text": "Set an alarm for 6:30 PM" + }, { "index": 1, "role": "assistant", "text": "Alarm set.", "apis": [{ - "request": {"api_name": "AddAlarm", "parameters": { - "session_token": "98a5a87a-7714-b404", "time": "18:30:00", - }}, - "response": {"alarm_id": "5bff-dd80"}, + "request": { + "api_name": "AddAlarm", + "parameters": { + "session_token": "98a5a87a-7714-b404", + "time": "18:30:00", + } + }, + "response": { + "alarm_id": "5bff-dd80" + }, "exception": None, }], "predictions": predictions, @@ -94,19 +105,28 @@ def test_single_correct_prediction_is_success(self, database_dir): predictions = [ { "role": "api", - "request": {"api_name": "AddAlarm", "parameters": { - "session_token": "98a5a87a-7714-b404", "time": "18:30:00", - }}, - "response": {"alarm_id": "5bff-dd80"}, + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", + "time": "18:30:00", + } + }, + "response": { + "alarm_id": "5bff-dd80" + }, "exception": None, }, - {"role": "assistant", "text": "Alarm set."}, + { + "role": "assistant", "text": "Alarm set." + }, ] conv = _make_alarm_conversation(predictions) item = EvalInputItem( - id="reg-001", input_obj=json.dumps(conv), + id="reg-001", + input_obj=json.dumps(conv), expected_output_obj=json.dumps(conv), - output_obj=json.dumps(conv), full_dataset_entry=conv, + output_obj=json.dumps(conv), + full_dataset_entry=conv, ) result = _evaluate_single(item, database_dir) @@ -124,35 +144,54 @@ def test_correct_plus_extra_calls_has_bad_actions(self, database_dir): predictions = [ { "role": "api", - "request": {"api_name": "AddAlarm", "parameters": { - "session_token": "98a5a87a-7714-b404", "time": "18:30:00", - }}, - "response": {"alarm_id": "5bff-dd80"}, + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", + "time": "18:30:00", + } + }, + "response": { + "alarm_id": "5bff-dd80" + }, "exception": None, }, { "role": "api", - "request": {"api_name": "AddAlarm", "parameters": { - "session_token": "98a5a87a-7714-b404", "time": "18:30:00", - }}, - "response": {"alarm_id": "aaaa-bbbb"}, + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", + "time": "18:30:00", + } + }, + "response": { + "alarm_id": "aaaa-bbbb" + }, "exception": None, }, { "role": "api", - "request": {"api_name": "AddAlarm", "parameters": { - "session_token": "98a5a87a-7714-b404", "time": "18:30:00", - }}, - "response": {"alarm_id": "cccc-dddd"}, + "request": { + "api_name": "AddAlarm", "parameters": { + "session_token": "98a5a87a-7714-b404", + "time": "18:30:00", + } + }, + "response": { + "alarm_id": "cccc-dddd" + }, "exception": None, }, - {"role": "assistant", "text": "Alarm set."}, + { + "role": "assistant", "text": "Alarm set." + }, ] conv = _make_alarm_conversation(predictions) item = EvalInputItem( - id="reg-002", input_obj=json.dumps(conv), + id="reg-002", + input_obj=json.dumps(conv), expected_output_obj=json.dumps(conv), - output_obj=json.dumps(conv), full_dataset_entry=conv, + output_obj=json.dumps(conv), + full_dataset_entry=conv, ) result = _evaluate_single(item, database_dir) @@ -169,19 +208,27 @@ def test_wrong_api_call_zero_recall(self, database_dir): predictions = [ { "role": "api", - "request": {"api_name": "DeleteAlarm", "parameters": { - "session_token": "98a5a87a-7714-b404", "alarm_id": "5bff-dd80", - }}, + "request": { + "api_name": "DeleteAlarm", + "parameters": { + "session_token": "98a5a87a-7714-b404", + "alarm_id": "5bff-dd80", + } + }, "response": None, "exception": "Alarm not found", }, - {"role": "assistant", "text": "Done."}, + { + "role": "assistant", "text": "Done." + }, ] conv = _make_alarm_conversation(predictions) item = EvalInputItem( - id="reg-003", input_obj=json.dumps(conv), + id="reg-003", + input_obj=json.dumps(conv), expected_output_obj=json.dumps(conv), - output_obj=json.dumps(conv), full_dataset_entry=conv, + output_obj=json.dumps(conv), + full_dataset_entry=conv, ) result = _evaluate_single(item, database_dir) @@ -192,13 +239,17 @@ def test_wrong_api_call_zero_recall(self, database_dir): def test_no_predictions_zero_recall(self, database_dir): """No API predictions at all = recall 0.""" predictions = [ - {"role": "assistant", "text": "I can't do that."}, + { + "role": "assistant", "text": "I can't do that." + }, ] conv = _make_alarm_conversation(predictions) item = EvalInputItem( - id="reg-004", input_obj=json.dumps(conv), + id="reg-004", + input_obj=json.dumps(conv), expected_output_obj=json.dumps(conv), - output_obj=json.dumps(conv), full_dataset_entry=conv, + output_obj=json.dumps(conv), + full_dataset_entry=conv, ) result = _evaluate_single(item, database_dir) diff --git a/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py b/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py index 80729a3b39..91538c933d 100644 --- a/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py +++ b/packages/nvidia_nat_core/tests/nat/builder/test_per_user_function_group_eval_isolation.py @@ -33,22 +33,26 @@ from uuid import uuid4 import pytest -from pydantic import BaseModel, Field +from pydantic import BaseModel +from pydantic import Field from nat.builder.builder import Builder from nat.builder.function import FunctionGroup from nat.builder.function_info import FunctionInfo from nat.builder.workflow_builder import WorkflowBuilder -from nat.cli.register_workflow import register_per_user_function_group, register_per_user_function -from nat.data_models.config import Config, GeneralConfig -from nat.data_models.function import FunctionGroupBaseConfig, FunctionBaseConfig +from nat.cli.register_workflow import register_per_user_function +from nat.cli.register_workflow import register_per_user_function_group +from nat.data_models.config import Config +from nat.data_models.config import GeneralConfig +from nat.data_models.function import FunctionBaseConfig +from nat.data_models.function import FunctionGroupBaseConfig from nat.runtime.session import SessionManager - # --------------------------------------------------------------------------- # Schemas # --------------------------------------------------------------------------- + class IncrementInput(BaseModel): n: int = Field(default=1, description="Amount to add to the counter") @@ -66,6 +70,7 @@ class EchoInput(BaseModel): # Config types (unique names to avoid conflicts with other tests) # --------------------------------------------------------------------------- + class IsolationCounterGroupConfig(FunctionGroupBaseConfig, name="isolation_counter_group"): """Per-user function group with a counter — validates fresh-instance-per-user.""" initial_value: int = Field(default=0) @@ -87,6 +92,7 @@ class EchoWorkflowConfig(FunctionBaseConfig, name="isolation_echo_workflow"): # Component registrations # --------------------------------------------------------------------------- + @pytest.fixture(scope="module", autouse=True) def _register_components(): """Register test components once for the module.""" @@ -110,9 +116,13 @@ async def increment(inp: IncrementInput) -> CounterOutput: async def get_count(inp: IncrementInput) -> CounterOutput: return CounterOutput(count=counter["value"], instance_id=instance_id) - group.add_function(name="increment", fn=increment, input_schema=IncrementInput, + group.add_function(name="increment", + fn=increment, + input_schema=IncrementInput, description="Increment counter by n") - group.add_function(name="get_count", fn=get_count, input_schema=IncrementInput, + group.add_function(name="get_count", + fn=get_count, + input_schema=IncrementInput, description="Get current count without incrementing") yield group @@ -120,10 +130,9 @@ async def get_count(inp: IncrementInput) -> CounterOutput: # The workflow must be per-user so that SessionManager creates a # PerUserWorkflowBuilder per unique user_id (which instantiates per-user # function groups fresh for each user). - @register_per_user_function(config_type=EchoWorkflowConfig, - input_type=EchoInput, - single_output_type=str) + @register_per_user_function(config_type=EchoWorkflowConfig, input_type=EchoInput, single_output_type=str) async def echo_workflow(config: EchoWorkflowConfig, builder: Builder): + async def _echo(inp: EchoInput) -> str: return inp.text @@ -134,6 +143,7 @@ async def _echo(inp: EchoInput) -> str: # Helper: build a minimal Config using the per-user function group # --------------------------------------------------------------------------- + def _make_config() -> Config: return Config( general=GeneralConfig(), @@ -146,6 +156,7 @@ def _make_config() -> Config: # Tests # --------------------------------------------------------------------------- + class TestPerUserFunctionGroupEvalIsolation: """ Validates that @register_per_user_function_group provides fresh instances @@ -188,8 +199,7 @@ async def test_different_user_ids_get_independent_counters(self): # Instance IDs must be different — they are separate objects assert result_a1.instance_id != result_b1.instance_id, ( - "Different user_ids must produce different function group instances" - ) + "Different user_ids must produce different function group instances") @pytest.mark.asyncio async def test_same_user_id_shares_state(self): @@ -269,5 +279,4 @@ async def simulate_eval_item(item_index: int) -> dict: # All instance_ids must be distinct — 3 separate objects instance_ids = {r["instance_id"] for r in results} assert len(instance_ids) == 3, ( - f"Expected 3 distinct function group instances, got {len(instance_ids)}: {instance_ids}" - ) + f"Expected 3 distinct function group instances, got {len(instance_ids)}: {instance_ids}") From 72c78b90c11321f5271f25a80d35de946d16a693 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 15:51:14 -0700 Subject: [PATCH 05/10] benchmark code reuse refactor Signed-off-by: Bryan Bednarski --- .../agent_leaderboard/pyproject.toml | 3 +- examples/benchmarks/bfcl/README.md | 10 +- examples/benchmarks/bfcl/pyproject.toml | 2 +- examples/benchmarks/byob/pyproject.toml | 3 +- examples/benchmarks/tooltalk/pyproject.toml | 2 +- packages/nvidia_nat_benchmarks/pyproject.toml | 21 +- .../benchmarks/agent_leaderboard/config.py | 49 +++- .../benchmarks/agent_leaderboard/evaluator.py | 86 +++--- .../benchmarks/agent_leaderboard/workflow.py | 7 +- .../src/nat/plugins/benchmarks/bfcl/config.py | 64 +++-- .../nat/plugins/benchmarks/bfcl/evaluator.py | 116 ++++---- .../benchmarks/bfcl/tool_intent_stubs.py | 269 +----------------- .../plugins/benchmarks/bfcl/workflow_ast.py | 16 +- .../plugins/benchmarks/bfcl/workflow_fc.py | 74 +---- .../plugins/benchmarks/bfcl/workflow_react.py | 161 ++++++----- .../nat/plugins/benchmarks/byob/evaluator.py | 52 ++-- .../nat/plugins/benchmarks/common/__init__.py | 14 + .../plugins/benchmarks/common/bfcl_helpers.py | 113 ++++++++ .../plugins/benchmarks/common/eval_helpers.py | 78 +++++ .../benchmarks/common/tool_intent_stubs.py | 245 ++++++++++++++++ .../nat/plugins/benchmarks/tooltalk/config.py | 25 +- .../plugins/benchmarks/tooltalk/evaluator.py | 59 ++-- .../plugins/benchmarks/tooltalk/workflow.py | 6 +- .../tests/common/__init__.py | 14 + .../tests/common/test_bfcl_helpers.py | 258 +++++++++++++++++ .../tests/common/test_config_enums.py | 222 +++++++++++++++ .../tests/common/test_eval_helpers.py | 139 +++++++++ 27 files changed, 1466 insertions(+), 642 deletions(-) create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/bfcl_helpers.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/eval_helpers.py create mode 100644 packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py create mode 100644 packages/nvidia_nat_benchmarks/tests/common/__init__.py create mode 100644 packages/nvidia_nat_benchmarks/tests/common/test_bfcl_helpers.py create mode 100644 packages/nvidia_nat_benchmarks/tests/common/test_config_enums.py create mode 100644 packages/nvidia_nat_benchmarks/tests/common/test_eval_helpers.py diff --git a/examples/benchmarks/agent_leaderboard/pyproject.toml b/examples/benchmarks/agent_leaderboard/pyproject.toml index c14fc18c38..739407b612 100644 --- a/examples/benchmarks/agent_leaderboard/pyproject.toml +++ b/examples/benchmarks/agent_leaderboard/pyproject.toml @@ -34,8 +34,7 @@ classifiers = ["Programming Language :: Python"] [tool.setuptools_dynamic_dependencies] dependencies = [ "nvidia-nat[eval,langchain,test] == {version}", - "nvidia-nat-benchmarks == {version}", - "datasets~=3.0", + "nvidia-nat-benchmarks[agent-leaderboard] == {version}", ] [tool.uv.sources] diff --git a/examples/benchmarks/bfcl/README.md b/examples/benchmarks/bfcl/README.md index 71c61b9b3d..23300d3531 100644 --- a/examples/benchmarks/bfcl/README.md +++ b/examples/benchmarks/bfcl/README.md @@ -49,12 +49,18 @@ uv pip install -e examples/benchmarks/bfcl ### Prerequisites -The NVIDIA `bfcl` package must be installed (includes datasets and AST checker): +The NVIDIA `nvidia-bfcl` package must be installed (includes datasets and AST checker). +Due to an overly restrictive `numpy==1.26.4` pin in `nvidia-bfcl` that conflicts with +NAT's `numpy>=2.3`, install it with `--no-deps`: ```bash -pip install nvidia-bfcl +uv pip install nvidia-bfcl --no-deps ``` +> `nvidia-bfcl` works correctly with numpy 2.x at runtime — the pin is a packaging +> constraint only. The `[bfcl]` extra in `nvidia-nat-benchmarks` installs the required +> `tree-sitter` dependencies automatically. + --- ## Set Up Environment diff --git a/examples/benchmarks/bfcl/pyproject.toml b/examples/benchmarks/bfcl/pyproject.toml index b14fb3bd71..605d0814ea 100644 --- a/examples/benchmarks/bfcl/pyproject.toml +++ b/examples/benchmarks/bfcl/pyproject.toml @@ -34,7 +34,7 @@ classifiers = ["Programming Language :: Python"] [tool.setuptools_dynamic_dependencies] dependencies = [ "nvidia-nat[eval,langchain,test] == {version}", - "nvidia-nat-benchmarks == {version}", + "nvidia-nat-benchmarks[bfcl] == {version}", ] [tool.uv.sources] diff --git a/examples/benchmarks/byob/pyproject.toml b/examples/benchmarks/byob/pyproject.toml index c425044c4d..fdf804690a 100644 --- a/examples/benchmarks/byob/pyproject.toml +++ b/examples/benchmarks/byob/pyproject.toml @@ -34,8 +34,7 @@ classifiers = ["Programming Language :: Python"] [tool.setuptools_dynamic_dependencies] dependencies = [ "nvidia-nat[eval,langchain,test] == {version}", - "nvidia-nat-benchmarks == {version}", - "nemo-evaluator", + "nvidia-nat-benchmarks[byob] == {version}", ] [tool.uv.sources] diff --git a/examples/benchmarks/tooltalk/pyproject.toml b/examples/benchmarks/tooltalk/pyproject.toml index 6632196f0e..8c73b08314 100644 --- a/examples/benchmarks/tooltalk/pyproject.toml +++ b/examples/benchmarks/tooltalk/pyproject.toml @@ -34,7 +34,7 @@ classifiers = ["Programming Language :: Python"] [tool.setuptools_dynamic_dependencies] dependencies = [ "nvidia-nat[eval,langchain,test] == {version}", - "nvidia-nat-benchmarks == {version}", + "nvidia-nat-benchmarks[tooltalk] == {version}", ] [tool.uv.sources] diff --git a/packages/nvidia_nat_benchmarks/pyproject.toml b/packages/nvidia_nat_benchmarks/pyproject.toml index 666239ef50..8de590a26b 100644 --- a/packages/nvidia_nat_benchmarks/pyproject.toml +++ b/packages/nvidia_nat_benchmarks/pyproject.toml @@ -59,12 +59,29 @@ dependencies = [ [tool.setuptools_dynamic_dependencies.optional-dependencies] tooltalk = [ - "tooltalk", + "nvidia-tooltalk", +] +bfcl = [ + # nvidia-bfcl must be installed separately with --no-deps due to an overly + # restrictive numpy==1.26.4 pin that conflicts with nvidia-nat-core (numpy>=2.3). + # Install manually: uv pip install nvidia-bfcl --no-deps + "tree-sitter~=0.21.0", + "tree-sitter-java~=0.21.0", + "tree-sitter-javascript~=0.21.0", +] +byob = [ + "nemo-evaluator", +] +agent-leaderboard = [ + "datasets~=4.4", +] +all = [ + "nvidia-nat-benchmarks[tooltalk,bfcl,byob,agent-leaderboard] == {version}", ] test = [ "nvidia-nat-core[async_endpoints] == {version}", "nvidia-nat-test == {version}", - "tooltalk", + "nvidia-nat-benchmarks[all] == {version}", ] [tool.uv] diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py index d321680fd2..3f23440069 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/config.py @@ -15,14 +15,25 @@ """Configuration types for Galileo Agent Leaderboard v2 benchmark.""" from collections.abc import Callable +from enum import StrEnum from pydantic import Field +from pydantic import PositiveInt +from pydantic import field_validator from nat.data_models.agent import AgentBaseConfig from nat.data_models.dataset_handler import EvalDatasetBaseConfig from nat.data_models.evaluator import EvaluatorBaseConfig -AVAILABLE_DOMAINS = ["banking", "healthcare", "insurance", "investment", "telecom"] + +class AgentLeaderboardDomain(StrEnum): + """Available domains in the Galileo Agent Leaderboard v2 dataset.""" + + BANKING = "banking" + HEALTHCARE = "healthcare" + INSURANCE = "insurance" + INVESTMENT = "investment" + TELECOM = "telecom" class AgentLeaderboardDatasetConfig(EvalDatasetBaseConfig, name="agent_leaderboard"): @@ -32,18 +43,30 @@ class AgentLeaderboardDatasetConfig(EvalDatasetBaseConfig, name="agent_leaderboa Each scenario has a user message, user_goals, and available tools. """ - domains: list[str] = Field( - default=["banking"], - description=f"Domains to include: {AVAILABLE_DOMAINS}", + domains: list[AgentLeaderboardDomain] = Field( + default=[AgentLeaderboardDomain.BANKING], + description="Domains to include: banking, healthcare, insurance, investment, telecom", ) limit: int | None = Field( default=None, description="Max scenarios to load (for testing)", ) + @field_validator("domains") + @classmethod + def _validate_domains_non_empty(cls, v: list[AgentLeaderboardDomain]) -> list[AgentLeaderboardDomain]: + """Ensure at least one domain is specified.""" + if not v: + raise ValueError("At least one domain must be specified") + return v + def parser(self) -> tuple[Callable, dict]: from .dataset import load_agent_leaderboard_dataset - return load_agent_leaderboard_dataset, {"domains": self.domains, "limit": self.limit} + + return load_agent_leaderboard_dataset, { + "domains": [str(d) for d in self.domains], + "limit": self.limit, + } class AgentLeaderboardWorkflowConfig(AgentBaseConfig, name="agent_leaderboard_workflow"): @@ -54,7 +77,7 @@ class AgentLeaderboardWorkflowConfig(AgentBaseConfig, name="agent_leaderboard_wo """ description: str = Field(default="Agent Leaderboard Workflow") - max_steps: int = Field( + max_steps: PositiveInt = Field( default=10, description="Maximum tool-calling steps per scenario", ) @@ -72,5 +95,15 @@ class TSQEvaluatorConfig(EvaluatorBaseConfig, name="agent_leaderboard_tsq"): Computes F1 score between predicted and expected tool calls. """ - tool_weight: float = Field(default=1.0, description="Weight for tool selection accuracy") - parameter_weight: float = Field(default=0.0, description="Weight for parameter accuracy") + tool_weight: float = Field( + default=1.0, + ge=0.0, + le=1.0, + description="Weight for tool selection accuracy", + ) + parameter_weight: float = Field( + default=0.0, + ge=0.0, + le=1.0, + description="Weight for parameter accuracy", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py index 1ffff3c76e..ce99a89403 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/evaluator.py @@ -20,6 +20,7 @@ import json import logging +from functools import partial from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo @@ -29,6 +30,7 @@ from nat.data_models.evaluator import EvalOutput from nat.data_models.evaluator import EvalOutputItem +from ..common.eval_helpers import run_evaluator_loop from .config import TSQEvaluatorConfig logger = logging.getLogger(__name__) @@ -44,26 +46,18 @@ def _normalize_tool_name(name: str) -> str: return name.lower().strip().replace("_", "").replace("-", "") -def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: float) -> EvalOutputItem: - """Evaluate tool selection quality for a single scenario.""" - if item.output_obj is None: - return EvalOutputItem( - id=item.id, - score=0.0, - reasoning={"error": "No workflow output"}, - ) +def _parse_expected_tool_calls(item: EvalInputItem) -> list[dict]: + """Extract expected tool calls from the eval item, trying multiple locations. - # Parse predicted tool calls from workflow output - try: - predicted = json.loads(item.output_obj) if isinstance(item.output_obj, str) else item.output_obj - if not isinstance(predicted, list): - predicted = [] - except (json.JSONDecodeError, TypeError): - predicted = [] + The expected tool calls may be in full_dataset_entry, the 'question' field + within full_dataset_entry, or in input_obj as a last resort. - # Parse expected tool calls from ground truth - # The full_dataset_entry from DatasetHandler is a DataFrame row with 'question' as serialized JSON. - # We need to parse that JSON to get the actual entry with expected_tool_calls. + Args: + item: The evaluation input item. + + Returns: + List of expected tool call dicts. + """ full_entry = item.full_dataset_entry if isinstance(full_entry, str): try: @@ -73,10 +67,8 @@ def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: if not isinstance(full_entry, dict): full_entry = {} - # Check if expected_tool_calls is directly in full_entry expected = full_entry.get("expected_tool_calls", []) - # If not found, try parsing the 'question' field (which contains the serialized entry) if not expected and "question" in full_entry: try: question_data = json.loads(full_entry["question"]) if isinstance(full_entry["question"], @@ -86,7 +78,6 @@ def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: except (json.JSONDecodeError, TypeError): pass - # Also try input_obj as a last resort if not expected and item.input_obj: try: input_data = json.loads(item.input_obj) if isinstance(item.input_obj, str) else item.input_obj @@ -95,6 +86,28 @@ def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: except (json.JSONDecodeError, TypeError): pass + return expected + + +def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: float) -> EvalOutputItem: + """Evaluate tool selection quality for a single scenario.""" + if item.output_obj is None: + return EvalOutputItem( + id=item.id, + score=0.0, + reasoning={"error": "No workflow output"}, + ) + + # Parse predicted tool calls from workflow output + try: + predicted = json.loads(item.output_obj) if isinstance(item.output_obj, str) else item.output_obj + if not isinstance(predicted, list): + predicted = [] + except (json.JSONDecodeError, TypeError): + predicted = [] + + expected = _parse_expected_tool_calls(item) + # Calculate tool selection F1 predicted_tools = {_normalize_tool_name(tc.get("tool", "")) for tc in predicted} - {""} expected_tools = {_normalize_tool_name(tc.get("tool", "")) for tc in expected} - {""} @@ -128,28 +141,19 @@ def _evaluate_single(item: EvalInputItem, tool_weight: float, parameter_weight: @register_evaluator(config_type=TSQEvaluatorConfig) async def agent_leaderboard_tsq_evaluator(config: TSQEvaluatorConfig, builder: EvalBuilder): + """Register the Agent Leaderboard TSQ evaluator.""" async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: - eval_output_items = [] - - for item in eval_input.eval_input_items: - try: - output_item = _evaluate_single(item, config.tool_weight, config.parameter_weight) - except Exception as e: - logger.exception("Error evaluating TSQ for item %s: %s", item.id, e) - output_item = EvalOutputItem( - id=item.id, - score=0.0, - reasoning={"error": str(e)}, - ) - eval_output_items.append(output_item) - - scores = [i.score for i in eval_output_items if isinstance(i.score, (int, float))] - average_score = sum(scores) / len(scores) if scores else 0.0 - - logger.info("TSQ evaluation complete: avg_f1=%.3f across %d scenarios", average_score, len(scores)) - - return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) + """Evaluate tool selection quality for all scenarios.""" + return run_evaluator_loop( + eval_input, + evaluate_item_fn=partial( + _evaluate_single, + tool_weight=config.tool_weight, + parameter_weight=config.parameter_weight, + ), + benchmark_name="Agent Leaderboard TSQ", + ) yield EvaluatorInfo( config=config, diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py index 850f6807fa..f6bec80a9c 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/agent_leaderboard/workflow.py @@ -28,9 +28,9 @@ from nat.builder.function_info import FunctionInfo from nat.cli.register_workflow import register_function -from ..bfcl.tool_intent_stubs import ToolIntentBuffer -from ..bfcl.tool_intent_stubs import clear_global_intents -from ..bfcl.tool_intent_stubs import set_current_scenario_id +from ..common.tool_intent_stubs import ToolIntentBuffer +from ..common.tool_intent_stubs import clear_global_intents +from ..common.tool_intent_stubs import set_current_scenario_id from .config import AgentLeaderboardWorkflowConfig logger = logging.getLogger(__name__) @@ -62,6 +62,7 @@ def _tool_schema_to_openai(tool: dict) -> dict: framework_wrappers=[LLMFrameworkEnum.LANGCHAIN], ) async def agent_leaderboard_workflow(config: AgentLeaderboardWorkflowConfig, builder: Builder): + """Register the Agent Leaderboard workflow.""" from langchain_core.messages import AIMessage from langchain_core.messages import HumanMessage from langchain_core.messages import SystemMessage diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py index 2f21119dcf..deee56c8d0 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/config.py @@ -15,29 +15,37 @@ """Configuration types for the BFCL benchmark.""" from collections.abc import Callable +from enum import StrEnum +from typing import Literal from pydantic import Field +from pydantic import field_validator from nat.data_models.agent import AgentBaseConfig from nat.data_models.dataset_handler import EvalDatasetBaseConfig from nat.data_models.evaluator import EvaluatorBaseConfig -# Valid BFCL v3 single-turn AST test categories -BFCL_AST_CATEGORIES = [ - "simple", - "multiple", - "parallel", - "parallel_multiple", - "java", - "javascript", - "live_simple", - "live_multiple", - "live_parallel", - "live_parallel_multiple", - "irrelevance", - "live_irrelevance", - "live_relevance", -] + +class BFCLTestCategory(StrEnum): + """Valid BFCL v3 single-turn AST test categories.""" + + SIMPLE = "simple" + MULTIPLE = "multiple" + PARALLEL = "parallel" + PARALLEL_MULTIPLE = "parallel_multiple" + JAVA = "java" + JAVASCRIPT = "javascript" + LIVE_SIMPLE = "live_simple" + LIVE_MULTIPLE = "live_multiple" + LIVE_PARALLEL = "live_parallel" + LIVE_PARALLEL_MULTIPLE = "live_parallel_multiple" + IRRELEVANCE = "irrelevance" + LIVE_IRRELEVANCE = "live_irrelevance" + LIVE_RELEVANCE = "live_relevance" + + +# Type alias for the supported AST parsing languages +BFCLLanguage = Literal["Python", "Java", "JavaScript"] class BFCLDatasetConfig(EvalDatasetBaseConfig, name="bfcl"): @@ -46,8 +54,8 @@ class BFCLDatasetConfig(EvalDatasetBaseConfig, name="bfcl"): file_path should point to a BFCL v3 JSONL test file (e.g. BFCL_v3_simple.json). """ - test_category: str = Field( - default="simple", + test_category: BFCLTestCategory = Field( + default=BFCLTestCategory.SIMPLE, description="BFCL test category: simple, multiple, parallel, parallel_multiple, " "java, javascript, irrelevance, live_simple, etc.", ) @@ -58,6 +66,7 @@ class BFCLDatasetConfig(EvalDatasetBaseConfig, name="bfcl"): def parser(self) -> tuple[Callable, dict]: from .dataset import load_bfcl_dataset + return load_bfcl_dataset, {"test_category": self.test_category} @@ -65,7 +74,7 @@ class BFCLASTWorkflowConfig(AgentBaseConfig, name="bfcl_ast_workflow"): """Workflow config for BFCL AST (prompting) evaluation. The LLM receives function schemas as text in the system prompt and outputs - raw function call text (e.g. `func_name(param=value)`). No tools= parameter. + raw function call text (e.g. ``func_name(param=value)``). No tools= parameter. """ description: str = Field(default="BFCL AST Prompting Workflow") @@ -74,7 +83,7 @@ class BFCLASTWorkflowConfig(AgentBaseConfig, name="bfcl_ast_workflow"): class BFCLFCWorkflowConfig(AgentBaseConfig, name="bfcl_fc_workflow"): """Workflow config for BFCL Native FC evaluation. - Uses llm.bind_tools(schemas) + ainvoke() — Native Function Calling. + Uses ``llm.bind_tools(schemas)`` + ``ainvoke()`` — Native Function Calling. Extracts tool_calls from AIMessage and formats as BFCL expected output. """ @@ -87,11 +96,20 @@ class BFCLEvaluatorConfig(EvaluatorBaseConfig, name="bfcl_evaluator"): Calls BFCL's ast_checker directly in-process for scoring. """ - test_category: str = Field( - default="simple", + test_category: BFCLTestCategory = Field( + default=BFCLTestCategory.SIMPLE, description="BFCL test category (must match the dataset config).", ) - language: str = Field( + language: BFCLLanguage = Field( default="Python", description="Programming language for AST parsing: Python, Java, or JavaScript.", ) + + @field_validator("language") + @classmethod + def _validate_language_category_match(cls, v: str) -> str: + """Validate that language is a supported value.""" + valid = {"Python", "Java", "JavaScript"} + if v not in valid: + raise ValueError(f"language must be one of {valid}, got '{v}'") + return v diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py index 86519ebe3a..4edc2b1f58 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/evaluator.py @@ -20,6 +20,8 @@ import json import logging +import re +from functools import partial from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo @@ -29,6 +31,7 @@ from nat.data_models.evaluator import EvalOutput from nat.data_models.evaluator import EvalOutputItem +from ..common.eval_helpers import run_evaluator_loop from .config import BFCLEvaluatorConfig logger = logging.getLogger(__name__) @@ -36,17 +39,13 @@ def _extract_function_call(raw_output: str) -> str: """Extract function call text from model output, stripping markdown and prose.""" - import re - # Try to extract from markdown code blocks first (python, json, tool_code, or untagged) code_blocks = re.findall(r'```(?:python|tool_code|json)?\s*\n?(.*?)\n?```', raw_output, re.DOTALL) if code_blocks: block = code_blocks[-1].strip() - # If it's JSON with "name"/"parameters", convert to function call converted = _try_convert_json_to_call(block) if converted: return converted - # If it's Python code with imports, extract just the function call lines if block.startswith("import ") or block.startswith("from "): calls = _extract_calls_from_code(block) if calls: @@ -70,7 +69,6 @@ def _extract_function_call(raw_output: str) -> str: func_call_lines = [] for line in lines: stripped = line.strip() - # Remove common prefixes for prefix in ['tools.', '> ', '- ']: if stripped.startswith(prefix): stripped = stripped[len(prefix):] @@ -78,7 +76,6 @@ def _extract_function_call(raw_output: str) -> str: func_call_lines.append(stripped) if func_call_lines: - # Strip 'tools.' prefix from extracted calls func_call_lines = [re.sub(r'^tools\.', '', c) for c in func_call_lines] if len(func_call_lines) == 1: return func_call_lines[0] @@ -90,36 +87,31 @@ def _extract_function_call(raw_output: str) -> str: def _try_convert_json_to_call(text: str) -> str | None: """Try to parse JSON tool-call format and convert to Python function call.""" - import json as _json try: - obj = _json.loads(text) + obj = json.loads(text) if isinstance(obj, dict) and "name" in obj: name = obj["name"] params = obj.get("parameters", obj.get("arguments", {})) if isinstance(params, dict): param_strs = [f"{k}={repr(v)}" for k, v in params.items()] return f"{name}({', '.join(param_strs)})" - except (_json.JSONDecodeError, TypeError): + except (json.JSONDecodeError, TypeError): pass return None def _extract_calls_from_code(code: str) -> str | None: """Extract function call expressions from Python code (skip imports, assignments).""" - import re lines = code.strip().split('\n') calls = [] for line in lines: stripped = line.strip() - # Skip imports, print, assignments with = if stripped.startswith(("import ", "from ", "print(", "#", "def ", "return ")): continue - # Look for variable = func(...) patterns assign_match = re.match(r'^[a-zA-Z_]\w*\s*=\s*([a-zA-Z_]\w*(?:\.\w+)*\s*\(.*\))\s*$', stripped) if assign_match: calls.append(assign_match.group(1)) continue - # Look for bare function calls if re.match(r'^[a-zA-Z_]\w*(?:\.\w+)*\s*\(', stripped): calls.append(stripped) if calls: @@ -159,35 +151,10 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> # Handle irrelevance/relevance tests differently if "irrelevance" in test_category: - # For irrelevance: model should NOT produce a valid function call - try: - decoded = default_decode_ast_prompting(model_output_raw, language) - # If decoding succeeds and produces non-empty output, it's a failure - if decoded and any(decoded): - return EvalOutputItem( - id=item.id, - score=0.0, - reasoning={ - "error": "Model produced function call for irrelevance test", "decoded": str(decoded) - }, - ) - except Exception: - pass # Decode failure = success for irrelevance - return EvalOutputItem(id=item.id, score=1.0, reasoning={"status": "correct_irrelevance"}) + return _evaluate_irrelevance(item.id, model_output_raw, language) if "relevance" in test_category: - # For relevance: model should produce a valid function call (any) - try: - decoded = default_decode_ast_prompting(model_output_raw, language) - if decoded and any(decoded): - return EvalOutputItem(id=item.id, score=1.0, reasoning={"status": "correct_relevance"}) - except Exception: - pass - return EvalOutputItem( - id=item.id, - score=0.0, - reasoning={"error": "Model failed to produce function call for relevance test"}, - ) + return _evaluate_relevance(item.id, model_output_raw, language) # Standard AST evaluation: decode and check try: @@ -221,7 +188,7 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> is_valid = checker_result.get("valid", False) score = 1.0 if is_valid else 0.0 - reasoning = { + reasoning: dict = { "valid": is_valid, "raw_output": model_output_raw[:500], "decoded": str(decoded_output)[:500], @@ -233,37 +200,54 @@ def _evaluate_single(item: EvalInputItem, test_category: str, language: str) -> return EvalOutputItem(id=item.id, score=score, reasoning=reasoning) +def _evaluate_irrelevance(item_id: str, model_output_raw: str, language: str) -> EvalOutputItem: + """For irrelevance tests: model should NOT produce a valid function call.""" + from bfcl.model_handler.utils import default_decode_ast_prompting + + try: + decoded = default_decode_ast_prompting(model_output_raw, language) + if decoded and any(decoded): + return EvalOutputItem( + id=item_id, + score=0.0, + reasoning={ + "error": "Model produced function call for irrelevance test", "decoded": str(decoded) + }, + ) + except Exception: + pass # Decode failure = success for irrelevance + return EvalOutputItem(id=item_id, score=1.0, reasoning={"status": "correct_irrelevance"}) + + +def _evaluate_relevance(item_id: str, model_output_raw: str, language: str) -> EvalOutputItem: + """For relevance tests: model should produce a valid function call (any).""" + from bfcl.model_handler.utils import default_decode_ast_prompting + + try: + decoded = default_decode_ast_prompting(model_output_raw, language) + if decoded and any(decoded): + return EvalOutputItem(id=item_id, score=1.0, reasoning={"status": "correct_relevance"}) + except Exception: + pass + return EvalOutputItem( + id=item_id, + score=0.0, + reasoning={"error": "Model failed to produce function call for relevance test"}, + ) + + @register_evaluator(config_type=BFCLEvaluatorConfig) async def bfcl_evaluator_function(config: BFCLEvaluatorConfig, builder: EvalBuilder): + """Register the BFCL benchmark evaluator.""" async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: - eval_output_items = [] - - for item in eval_input.eval_input_items: - try: - output_item = _evaluate_single(item, config.test_category, config.language) - except Exception as e: - logger.exception("Error evaluating BFCL item %s: %s", item.id, e) - output_item = EvalOutputItem( - id=item.id, - score=0.0, - reasoning={"error": str(e)}, - ) - eval_output_items.append(output_item) - - scores = [i.score for i in eval_output_items if isinstance(i.score, (int, float))] - average_score = sum(scores) / len(scores) if scores else 0.0 - - logger.info( - "BFCL evaluation complete: accuracy=%.3f (%d/%d) category=%s", - average_score, - sum(1 for s in scores if s == 1.0), - len(scores), - config.test_category, + """Evaluate all items using BFCL's ast_checker.""" + return run_evaluator_loop( + eval_input, + evaluate_item_fn=partial(_evaluate_single, test_category=config.test_category, language=config.language), + benchmark_name=f"BFCL ({config.test_category})", ) - return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) - yield EvaluatorInfo( config=config, evaluate_fn=evaluate_fn, diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py index fccfc15803..27dbf0047b 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/tool_intent_stubs.py @@ -12,263 +12,18 @@ # 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. -""" -Tool Intent Stub System for Decision-Only Evaluation. +"""Re-export from common.tool_intent_stubs for backward compatibility. -This module provides a mechanism to capture tool-intent decisions without executing actual tools. -Each stub: -1. Reads expected parameters from the tool schema -2. Records the invocation (tool_name, parameters) to a shared buffer -3. Returns a canned response so the agent continues reasoning +The canonical location is now ``common.tool_intent_stubs``. """ -import contextvars -import json -import logging -from typing import Any - -from pydantic import BaseModel -from pydantic import field_validator - -logger = logging.getLogger(__name__) - -# Global registry for tool intents (accessible across module) -# This allows evaluators to retrieve captured intents -_GLOBAL_INTENT_REGISTRY: dict[str, list[dict[str, Any]]] = {} - -# Context variable for current scenario ID (async-safe for concurrent execution isolation) -# Unlike threading.local(), contextvars work correctly with asyncio tasks -_current_scenario_id: contextvars.ContextVar[str] = contextvars.ContextVar("scenario_id", default="current") - - -def set_current_scenario_id(scenario_id: str) -> contextvars.Token: - """ - Set the current scenario ID for this async context. - - This allows concurrent async workflows to isolate their intents. - Call this before executing a workflow to ensure intents are recorded - to the correct scenario. - - Args: - scenario_id: Unique identifier for the current scenario/question - - Returns: - Token that can be used to reset the scenario ID (for cleanup) - """ - token = _current_scenario_id.set(scenario_id) - # Initialize registry entry if needed - if scenario_id not in _GLOBAL_INTENT_REGISTRY: - _GLOBAL_INTENT_REGISTRY[scenario_id] = [] - logger.debug("Set current scenario ID to: %s", scenario_id) - return token - - -def get_current_scenario_id() -> str: - """ - Get the current scenario ID for this async context. - - Returns: - The current scenario ID, or "current" if not set - """ - return _current_scenario_id.get() - - -class ToolIntentBuffer: - """ - Shared buffer to store tool intent captures during agent execution. - - This is used in decision-only mode to track which tools the agent - decided to call and with what parameters, without actually executing them. - - Uses a global registry so evaluators can access intents across the codebase. - The buffer uses the current scenario ID from the contextvar (set via - set_current_scenario_id) for both recording and clearing intents. - """ - - def __init__(self) -> None: - """Initialize a tool intent buffer.""" - self.intents: list[dict[str, Any]] = [] - - def record(self, tool_name: str, parameters: dict[str, Any]) -> None: - """ - Record a tool intent. - - Args: - tool_name: Name of the tool the agent decided to call - parameters: Parameters the agent provided for the tool call - """ - intent = {"tool": tool_name, "parameters": parameters} - self.intents.append(intent) - - # Store in global registry using contextvar scenario ID for concurrent isolation - current_scenario = get_current_scenario_id() - if current_scenario not in _GLOBAL_INTENT_REGISTRY: - _GLOBAL_INTENT_REGISTRY[current_scenario] = [] - _GLOBAL_INTENT_REGISTRY[current_scenario].append(intent) - - logger.debug("Recorded tool intent: %s (scenario: %s)", tool_name, current_scenario) - - def get_intents(self) -> list[dict[str, Any]]: - """ - Get all recorded tool intents. - - Returns: - List of tool intents with format [{"tool": "name", "parameters": {...}}] - """ - return self.intents.copy() - - def clear(self) -> None: - """Clear all recorded intents for the current scenario.""" - self.intents.clear() - # Clear from global registry using contextvar (aligned with record()) - current_scenario = get_current_scenario_id() - _GLOBAL_INTENT_REGISTRY[current_scenario] = [] - logger.debug("Cleared tool intent buffer for scenario %s", current_scenario) - - -def get_global_intents(scenario_id: str = "current") -> list[dict[str, Any]]: - """ - Retrieve tool intents from the global registry. - - This allows evaluators to access intents without needing builder access. - - Args: - scenario_id: Identifier for the scenario - - Returns: - List of tool intents - """ - return _GLOBAL_INTENT_REGISTRY.get(scenario_id, []).copy() - - -def clear_global_intents(scenario_id: str = "current") -> None: - """ - Clear intents from global registry. - - Args: - scenario_id: Identifier for the scenario to clear - """ - if scenario_id in _GLOBAL_INTENT_REGISTRY: - _GLOBAL_INTENT_REGISTRY[scenario_id] = [] - logger.debug("Cleared global intents for scenario %s", scenario_id) - - -class PermissiveToolInput(BaseModel): - """ - Input schema that accepts tool parameters as either dict or JSON string. - - This handles the case where LangChain sometimes serializes tool inputs - as JSON strings before passing them to the tool, while NAT expects dicts. - """ - input_params: dict[str, Any] | str - - @field_validator('input_params', mode='before') - @classmethod - def parse_string_to_dict(cls, v: Any) -> dict[str, Any]: - """Convert JSON string to dict if needed.""" - if isinstance(v, str): - try: - # Handle both single and double quotes in JSON strings - normalized = v.replace("'", '"') - return json.loads(normalized) - except json.JSONDecodeError: - logger.warning("Failed to parse input_params string as JSON: %s", v[:100]) - return {} - elif isinstance(v, dict): - return v - else: - logger.warning("Unexpected input_params type: %s", type(v)) - return {} - - -def create_tool_stub_function(tool_schema: dict[str, Any], - intent_buffer: ToolIntentBuffer, - canned_response: str | None = None) -> tuple[callable, BaseModel | None, str]: - """ - Create a stub function for a tool that captures intent without executing. - - Args: - tool_schema: Tool schema from the dataset (includes title, description, properties, required) - intent_buffer: Shared buffer to record tool intents - canned_response: Optional canned response to return (defaults to success message) - - Returns: - Tuple of (async_function, input_schema, function_description) - Note: Returns custom input_schema with no validation to accept any parameter format - """ - tool_name = tool_schema.get("title", "unknown_tool") - tool_description = tool_schema.get("description", "") - - # Default canned response - if canned_response is None: - response_schema = tool_schema.get("response_schema", {}) - if response_schema: - # Generate a realistic-looking response based on schema - canned_response = json.dumps(_generate_mock_response(response_schema), indent=2) - else: - canned_response = f"Successfully executed {tool_name}. Operation completed." - - # Create stub function that accepts object input (broadest concrete type) - # The PermissiveToolInput validator will handle string-to-dict conversion - async def tool_stub_fn(input_params: object) -> str: - """Tool stub that captures intent without executing.""" - # At this point, input_params should be a dict thanks to the Pydantic validator - # Handle nested 'params' dict from LangChain if present - if isinstance(input_params, dict): - if 'params' in input_params and isinstance(input_params['params'], dict): - params_dict = input_params['params'] - else: - params_dict = input_params - else: - # Fallback in case validation didn't run - logger.warning("input_params is not a dict: %s", type(input_params)) - params_dict = {} - - # Filter out None values - if isinstance(params_dict, dict): - params_dict = {k: v for k, v in params_dict.items() if v is not None} - intent_buffer.record(tool_name, params_dict) - logger.info("Tool stub executed: %s with %d parameters", tool_name, len(params_dict)) - return canned_response - - # Set proper attributes - tool_stub_fn.__name__ = tool_name - tool_stub_fn.__doc__ = tool_description - - # Return function WITH custom input_schema that accepts both dict and string - return tool_stub_fn, PermissiveToolInput, tool_description - - -def _generate_mock_response(response_schema: dict[str, Any]) -> dict[str, Any]: - """ - Generate a mock response based on the response schema. - - Args: - response_schema: Response schema from the tool definition - - Returns: - Dictionary with mock values matching the schema - """ - mock_response = {} - properties = response_schema.get("properties", {}) - - for prop_name, prop_info in properties.items(): - prop_type = prop_info.get("type", "string") - - # Generate mock values based on type - if prop_type == "string": - mock_response[prop_name] = f"mock_{prop_name}" - elif prop_type == "integer": - mock_response[prop_name] = 100 - elif prop_type == "number": - mock_response[prop_name] = 100.50 - elif prop_type == "boolean": - mock_response[prop_name] = True - elif prop_type == "array": - mock_response[prop_name] = [] - elif prop_type == "object": - mock_response[prop_name] = {} - else: - mock_response[prop_name] = None - - return mock_response +from nat.plugins.benchmarks.common.tool_intent_stubs import _GLOBAL_INTENT_REGISTRY # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import PermissiveToolInput # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import ToolIntentBuffer # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import _current_scenario_id # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import _generate_mock_response # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import clear_global_intents # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import create_tool_stub_function # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import get_current_scenario_id # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import get_global_intents # noqa: F401 +from nat.plugins.benchmarks.common.tool_intent_stubs import set_current_scenario_id # noqa: F401 diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py index 32fb9e266b..f04f6ca78f 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_ast.py @@ -15,7 +15,7 @@ """BFCL AST (prompting) workflow. Serializes function schemas as text in the system prompt and makes a single -LLM call. The model outputs raw function call text (e.g. `func(param=val)`) +LLM call. The model outputs raw function call text (e.g. ``func(param=val)``) which BFCL's ast_checker can parse. """ @@ -27,6 +27,7 @@ from nat.builder.function_info import FunctionInfo from nat.cli.register_workflow import register_function +from ..common.bfcl_helpers import extract_user_message from .config import BFCLASTWorkflowConfig logger = logging.getLogger(__name__) @@ -44,12 +45,12 @@ "[func_name1(params_name1=params_value1, params_name2=params_value2...), func_name2(params)]\n" "You SHOULD NOT include any other text in the response.\n\n" "Here is a list of functions in JSON format that you can invoke.\n" - "{functions_json}\n" -) + "{functions_json}\n") @register_function(config_type=BFCLASTWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def bfcl_ast_workflow(config: BFCLASTWorkflowConfig, builder: Builder): + """Register the BFCL AST prompting workflow.""" from langchain_core.messages import HumanMessage from langchain_core.messages import SystemMessage @@ -61,16 +62,9 @@ async def _run(input_json: str) -> str: functions = entry.get("function", []) question_turns = entry.get("question", [[]]) - # Build system message with function schemas functions_json = json.dumps(functions, indent=2) system_msg = SystemMessage(content=SYSTEM_PROMPT.format(functions_json=functions_json)) - - # Build user message(s) — BFCL uses the last turn's last message - user_content = "" - for turn in question_turns: - for msg in turn: - if msg.get("role") == "user": - user_content = msg["content"] + user_content = extract_user_message(question_turns) messages = [system_msg, HumanMessage(content=user_content)] response = await llm.ainvoke(messages) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py index ba43e4bfd3..1467dffe9d 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_fc.py @@ -14,7 +14,7 @@ # limitations under the License. """BFCL Native FC workflow. -Uses llm.bind_tools(schemas) + ainvoke() to make the LLM produce structured +Uses ``llm.bind_tools(schemas)`` + ``ainvoke()`` to make the LLM produce structured tool_calls via the native function calling API. Extracts tool_calls from AIMessage and formats them for BFCL's ast_checker. """ @@ -27,53 +27,17 @@ from nat.builder.function_info import FunctionInfo from nat.cli.register_workflow import register_function +from ..common.bfcl_helpers import convert_bfcl_schema_to_openai +from ..common.bfcl_helpers import extract_user_message +from ..common.bfcl_helpers import format_tool_calls_as_bfcl from .config import BFCLFCWorkflowConfig logger = logging.getLogger(__name__) -# Map BFCL type names to OpenAPI/JSON Schema types -GORILLA_TO_OPENAPI = { - "integer": "integer", - "number": "number", - "float": "number", - "string": "string", - "boolean": "boolean", - "array": "array", - "dict": "object", - "object": "object", - "tuple": "array", - "any": "string", - "String": "string", - "int": "integer", -} - - -def _convert_bfcl_schema_to_openai(func: dict) -> dict: - """Convert a BFCL function schema to OpenAI function calling format.""" - params = func.get("parameters", {}) - properties = {} - for name, prop in params.get("properties", {}).items(): - converted = dict(prop) - if "type" in converted: - converted["type"] = GORILLA_TO_OPENAPI.get(converted["type"], converted["type"]) - properties[name] = converted - - return { - "type": "function", - "function": { - "name": func["name"], - "description": func.get("description", ""), - "parameters": { - "type": "object", - "properties": properties, - "required": params.get("required", []), - }, - }, - } - @register_function(config_type=BFCLFCWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def bfcl_fc_workflow(config: BFCLFCWorkflowConfig, builder: Builder): + """Register the BFCL Native FC workflow.""" from langchain_core.messages import HumanMessage llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) @@ -84,35 +48,17 @@ async def _run(input_json: str) -> str: functions = entry.get("function", []) question_turns = entry.get("question", [[]]) - # Convert BFCL schemas to OpenAI tool format - tools = [_convert_bfcl_schema_to_openai(f) for f in functions] + tools = [convert_bfcl_schema_to_openai(f) for f in functions] bound_llm = llm.bind_tools(tools) - - # Get user message - user_content = "" - for turn in question_turns: - for msg in turn: - if msg.get("role") == "user": - user_content = msg["content"] + user_content = extract_user_message(question_turns) response = await bound_llm.ainvoke([HumanMessage(content=user_content)]) if not response.tool_calls: - # No tool calls — return empty (will be scored as failure for non-irrelevance tests) return str(response.content) - # Format tool calls as BFCL expects: - # List of function call strings like: func_name(param1=val1, param2=val2) - call_strs = [] - for tc in response.tool_calls: - name = tc["name"] - args = tc["args"] - # Format as Python function call string for AST parsing - param_strs = [] - for k, v in args.items(): - param_strs.append(f"{k}={repr(v)}") - call_strs.append(f"{name}({', '.join(param_strs)})") - - return "[" + ", ".join(call_strs) + "]" + # Format tool calls using the shared helper + formatted_calls = [{"name": tc["name"], "args": tc["args"]} for tc in response.tool_calls] + return format_tool_calls_as_bfcl(formatted_calls) yield FunctionInfo.from_fn(_run, description=config.description) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py index 8caa36f105..fef8ac5f19 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/bfcl/workflow_react.py @@ -26,6 +26,7 @@ import logging from pydantic import Field +from pydantic import PositiveInt from nat.builder.builder import Builder from nat.builder.framework_enum import LLMFrameworkEnum @@ -33,10 +34,12 @@ from nat.cli.register_workflow import register_function from nat.data_models.agent import AgentBaseConfig -from .tool_intent_stubs import ToolIntentBuffer -from .tool_intent_stubs import clear_global_intents -from .tool_intent_stubs import set_current_scenario_id -from .workflow_fc import _convert_bfcl_schema_to_openai +from ..common.bfcl_helpers import convert_bfcl_schema_to_openai +from ..common.bfcl_helpers import extract_user_message +from ..common.bfcl_helpers import format_tool_calls_as_bfcl +from ..common.tool_intent_stubs import ToolIntentBuffer +from ..common.tool_intent_stubs import clear_global_intents +from ..common.tool_intent_stubs import set_current_scenario_id logger = logging.getLogger(__name__) @@ -50,14 +53,65 @@ class BFCLReActWorkflowConfig(AgentBaseConfig, name="bfcl_react_workflow"): """ description: str = Field(default="BFCL ReAct Workflow") - max_steps: int = Field( + max_steps: PositiveInt = Field( default=5, description="Maximum number of ReAct reasoning/action steps per item", ) +def _coerce_args(args: dict, param_types: dict[str, str]) -> dict: + """Coerce tool call arguments to expected types from BFCL schema. + + LLMs sometimes return string representations of integers/floats/booleans. + This converts them to the expected Python types based on the schema. + + Args: + args: The raw arguments dict from the LLM tool call. + param_types: Mapping of parameter name to BFCL type string. + + Returns: + A new dict with coerced values. + """ + coerced = dict(args) + for k, v in coerced.items(): + expected = param_types.get(k, "string") + if expected in ("integer", "int") and isinstance(v, str): + try: + coerced[k] = int(v) + except ValueError: + pass + elif expected in ("float", "number") and isinstance(v, str): + try: + coerced[k] = float(v) + except ValueError: + pass + elif expected == "boolean" and isinstance(v, str): + coerced[k] = v.lower() in ("true", "1", "yes") + return coerced + + +def _deduplicate_intents(intents: list[dict]) -> list[dict]: + """Deduplicate intents (same tool + same params = single call). + + Args: + intents: List of intent dicts with "tool" and "parameters" keys. + + Returns: + Deduplicated list preserving first occurrence order. + """ + seen: set[tuple[str, str]] = set() + unique = [] + for intent in intents: + key = (intent["tool"], json.dumps(intent["parameters"], sort_keys=True)) + if key not in seen: + seen.add(key) + unique.append(intent) + return unique + + @register_function(config_type=BFCLReActWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def bfcl_react_workflow(config: BFCLReActWorkflowConfig, builder: Builder): + """Register the BFCL ReAct workflow.""" from langchain_core.messages import AIMessage from langchain_core.messages import HumanMessage from langchain_core.messages import SystemMessage @@ -66,7 +120,7 @@ async def bfcl_react_workflow(config: BFCLReActWorkflowConfig, builder: Builder) llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN) async def _run(input_json: str) -> str: - """ReAct loop: reason → call tool stubs → observe → repeat → output intents.""" + """ReAct loop: reason -> call tool stubs -> observe -> repeat -> output intents.""" entry = json.loads(input_json) functions = entry.get("function", []) question_turns = entry.get("question", [[]]) @@ -78,103 +132,48 @@ async def _run(input_json: str) -> str: intent_buffer = ToolIntentBuffer() try: - # Convert BFCL schemas to OpenAI tool format - tools = [_convert_bfcl_schema_to_openai(f) for f in functions] + tools = [convert_bfcl_schema_to_openai(f) for f in functions] bound_llm = llm.bind_tools(tools) # Build type map for coercing args to expected types - param_types = {} # {func_name: {param_name: bfcl_type}} + param_types: dict[str, dict[str, str]] = {} for f in functions: props = f.get("parameters", {}).get("properties", {}) param_types[f["name"]] = {k: v.get("type", "string") for k, v in props.items()} - # Get user message - user_content = "" - for turn in question_turns: - for msg in turn: - if msg.get("role") == "user": - user_content = msg["content"] + user_content = extract_user_message(question_turns) - # Build initial messages - system_msg = SystemMessage( - content="You are a helpful assistant. Use the provided tools to answer the user's request. " - "Think step by step about which tool(s) to call and with what parameters.") - messages = [system_msg, HumanMessage(content=user_content)] + messages = [ + SystemMessage( + content="You are a helpful assistant. Use the provided tools to answer the user's request. " + "Think step by step about which tool(s) to call and with what parameters."), + HumanMessage(content=user_content), + ] - # ReAct loop for step in range(config.max_steps): response = await bound_llm.ainvoke(messages) if not response.tool_calls: - # Agent decided it's done — no more tool calls break - # Process all tool calls in this step for tc in response.tool_calls: name = tc["name"] - args = dict(tc["args"]) - - # Coerce args to expected types from BFCL schema - types = param_types.get(name, {}) - for k, v in args.items(): - expected = types.get(k, "string") - if expected in ("integer", "int") and isinstance(v, str): - try: - args[k] = int(v) - except ValueError: - pass - elif expected in ("float", "number") and isinstance(v, str): - try: - args[k] = float(v) - except ValueError: - pass - elif expected == "boolean" and isinstance(v, str): - args[k] = v.lower() in ("true", "1", "yes") - - # Record intent + args = _coerce_args(dict(tc["args"]), param_types.get(name, {})) + intent_buffer.record(name, args) - # Return canned response so the agent can continue canned = f"Successfully executed {name}. Operation completed." - - # Add the assistant message with tool call + tool response - messages.append( - AIMessage( - content="", - tool_calls=[{ - "name": name, - "args": args, - "id": tc.get("id", f"call_{step}_{name}"), - }], - )) - messages.append(ToolMessage( - content=canned, - tool_call_id=tc.get("id", f"call_{step}_{name}"), + tc_id = tc.get("id", f"call_{step}_{name}") + messages.append(AIMessage( + content="", + tool_calls=[{ + "name": name, "args": args, "id": tc_id + }], )) + messages.append(ToolMessage(content=canned, tool_call_id=tc_id)) - # Format captured intents as BFCL-compatible output - intents = intent_buffer.get_intents() - if not intents: - return "" - - # Deduplicate intents (same tool + same params = single call) - seen = set() - unique_intents = [] - for intent in intents: - key = (intent["tool"], json.dumps(intent["parameters"], sort_keys=True)) - if key not in seen: - seen.add(key) - unique_intents.append(intent) - - # Format as Python function call strings for AST parsing - call_strs = [] - for intent in unique_intents: - name = intent["tool"] - params = intent["parameters"] - param_strs = [f"{k}={repr(v)}" for k, v in params.items()] - call_strs.append(f"{name}({', '.join(param_strs)})") - - return "[" + ", ".join(call_strs) + "]" + intents = _deduplicate_intents(intent_buffer.get_intents()) + return format_tool_calls_as_bfcl(intents) finally: clear_global_intents(scenario_id) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py index e20af28b29..207c825568 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/byob/evaluator.py @@ -21,6 +21,7 @@ import json import logging +from functools import partial from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo @@ -30,6 +31,7 @@ from nat.data_models.evaluator import EvalOutput from nat.data_models.evaluator import EvalOutputItem +from ..common.eval_helpers import run_evaluator_loop from .config import BYOBEvaluatorConfig logger = logging.getLogger(__name__) @@ -98,46 +100,30 @@ def _evaluate_single( @register_evaluator(config_type=BYOBEvaluatorConfig) async def byob_evaluator_function(config: BYOBEvaluatorConfig, builder: EvalBuilder): + """Register the BYOB benchmark evaluator.""" from nemo_evaluator.contrib.byob.eval_logic import import_benchmark bench = import_benchmark(config.benchmark_module, config.benchmark_name) - logger.info("BYOB evaluator loaded benchmark '%s' with scorer '%s'", - bench.name, - getattr(bench.scorer_fn, '__name__', 'unknown')) + logger.info( + "BYOB evaluator loaded benchmark '%s' with scorer '%s'", + bench.name, + getattr(bench.scorer_fn, '__name__', 'unknown'), + ) async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: - eval_output_items = [] - - for item in eval_input.eval_input_items: - try: - output_item = _evaluate_single( - item, - bench.scorer_fn, - bench.target_field, - config.score_field, - bench.extra_config, - ) - except Exception as e: - logger.exception("Error evaluating BYOB item %s: %s", item.id, e) - output_item = EvalOutputItem( - id=item.id, - score=0.0, - reasoning={"error": str(e)}, - ) - eval_output_items.append(output_item) - - scores = [i.score for i in eval_output_items if isinstance(i.score, (int, float))] - average_score = sum(scores) / len(scores) if scores else 0.0 - - logger.info( - "BYOB evaluation complete: avg_%s=%.3f (%d items)", - config.score_field, - average_score, - len(scores), + """Evaluate all items using the BYOB scorer.""" + return run_evaluator_loop( + eval_input, + evaluate_item_fn=partial( + _evaluate_single, + scorer_fn=bench.scorer_fn, + target_field=bench.target_field, + score_field=config.score_field, + extra_config=bench.extra_config, + ), + benchmark_name=f"BYOB ({config.benchmark_name})", ) - return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) - yield EvaluatorInfo( config=config, evaluate_fn=evaluate_fn, diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/__init__.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/__init__.py new file mode 100644 index 0000000000..bcd923c929 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/bfcl_helpers.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/bfcl_helpers.py new file mode 100644 index 0000000000..1ccc7c7038 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/bfcl_helpers.py @@ -0,0 +1,113 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Shared helpers for BFCL benchmark workflows. + +Provides common utilities shared across the AST, FC, and ReAct BFCL workflows. +""" + +# Map BFCL type names to OpenAPI/JSON Schema types +GORILLA_TO_OPENAPI: dict[str, str] = { + "integer": "integer", + "number": "number", + "float": "number", + "string": "string", + "boolean": "boolean", + "array": "array", + "dict": "object", + "object": "object", + "tuple": "array", + "any": "string", + "String": "string", + "int": "integer", +} + + +def extract_user_message(question_turns: list[list[dict]]) -> str: + """Extract the last user message from BFCL question turns. + + BFCL stores questions as nested lists of message dicts. This extracts + the content of the last user-role message across all turns. + + Args: + question_turns: Nested list of message dicts from BFCL entry["question"]. + + Returns: + The content string of the last user message, or empty string if none found. + """ + user_content = "" + for turn in question_turns: + for msg in turn: + if msg.get("role") == "user": + user_content = msg["content"] + return user_content + + +def convert_bfcl_schema_to_openai(func: dict) -> dict: + """Convert a BFCL function schema to OpenAI function calling format. + + BFCL uses its own type names (e.g., "integer", "float", "dict") which + need to be mapped to OpenAPI/JSON Schema types for the OpenAI tools= API. + + Args: + func: A BFCL function schema dict with "name", "description", and "parameters". + + Returns: + An OpenAI-format tool schema dict. + """ + params = func.get("parameters", {}) + properties = {} + for name, prop in params.get("properties", {}).items(): + converted = dict(prop) + if "type" in converted: + converted["type"] = GORILLA_TO_OPENAPI.get(converted["type"], converted["type"]) + properties[name] = converted + + return { + "type": "function", + "function": { + "name": func["name"], + "description": func.get("description", ""), + "parameters": { + "type": "object", + "properties": properties, + "required": params.get("required", []), + }, + }, + } + + +def format_tool_calls_as_bfcl(tool_calls: list[dict]) -> str: + """Format tool call dicts as BFCL-compatible function call strings. + + Converts a list of tool call dicts (with "name" and "args"/"parameters" keys) + to BFCL's expected AST format: ``[func_name(param1=val1, param2=val2)]``. + + Args: + tool_calls: List of dicts with "name" and "args" or "parameters" keys. + + Returns: + A BFCL-format function call string, or empty string if no calls. + """ + if not tool_calls: + return "" + + call_strs = [] + for tc in tool_calls: + name = tc.get("name", tc.get("tool", "")) + args = tc.get("args", tc.get("parameters", {})) + param_strs = [f"{k}={repr(v)}" for k, v in args.items()] + call_strs.append(f"{name}({', '.join(param_strs)})") + + return "[" + ", ".join(call_strs) + "]" diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/eval_helpers.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/eval_helpers.py new file mode 100644 index 0000000000..3e8db20d4d --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/eval_helpers.py @@ -0,0 +1,78 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Shared evaluation helpers for benchmark evaluators. + +Provides a common evaluator loop pattern used across all benchmark evaluators +to reduce boilerplate and ensure consistent error handling. +""" + +import logging +from collections.abc import Callable + +from nat.data_models.evaluator import EvalInput +from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalOutput +from nat.data_models.evaluator import EvalOutputItem + +logger = logging.getLogger(__name__) + + +def run_evaluator_loop( + eval_input: EvalInput, + evaluate_item_fn: Callable[[EvalInputItem], EvalOutputItem], + benchmark_name: str, +) -> EvalOutput: + """Run the standard evaluator loop: score each item, handle errors, compute average. + + This is the shared pattern used by all benchmark evaluators. It: + 1. Iterates over all items in the eval input + 2. Calls evaluate_item_fn for each item + 3. Catches and logs exceptions, assigning score=0.0 for failed items + 4. Computes the average score across all items + 5. Logs a summary + + Args: + eval_input: The evaluation input containing all items to evaluate. + evaluate_item_fn: A callable that takes an EvalInputItem and returns an EvalOutputItem. + benchmark_name: Name of the benchmark (for logging). + + Returns: + EvalOutput with average score and per-item results. + """ + eval_output_items: list[EvalOutputItem] = [] + + for item in eval_input.eval_input_items: + try: + output_item = evaluate_item_fn(item) + except Exception as e: + logger.exception("Error evaluating %s item %s: %s", benchmark_name, item.id, e) + output_item = EvalOutputItem( + id=item.id, + score=0.0, + reasoning={"error": str(e)}, + ) + eval_output_items.append(output_item) + + scores = [item.score for item in eval_output_items if isinstance(item.score, (int, float))] + average_score = sum(scores) / len(scores) if scores else 0.0 + + logger.info( + "%s evaluation complete: avg_score=%.3f across %d items", + benchmark_name, + average_score, + len(scores), + ) + + return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py new file mode 100644 index 0000000000..24fcbd9815 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py @@ -0,0 +1,245 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +""" +Tool Intent Stub System for Decision-Only Evaluation. + +This module provides a mechanism to capture tool-intent decisions without executing actual tools. +Each stub: +1. Reads expected parameters from the tool schema +2. Records the invocation (tool_name, parameters) to a shared buffer +3. Returns a canned response so the agent continues reasoning +""" + +import contextvars +import json +import logging +from typing import Any + +from pydantic import BaseModel +from pydantic import field_validator + +logger = logging.getLogger(__name__) + +# Global registry for tool intents (accessible across module) +# This allows evaluators to retrieve captured intents +_GLOBAL_INTENT_REGISTRY: dict[str, list[dict[str, Any]]] = {} + +# Context variable for current scenario ID (async-safe for concurrent execution isolation) +# Unlike threading.local(), contextvars work correctly with asyncio tasks +_current_scenario_id: contextvars.ContextVar[str] = contextvars.ContextVar("scenario_id", default="current") + + +def set_current_scenario_id(scenario_id: str) -> contextvars.Token: + """Set the current scenario ID for this async context. + + This allows concurrent async workflows to isolate their intents. + Call this before executing a workflow to ensure intents are recorded + to the correct scenario. + + Args: + scenario_id: Unique identifier for the current scenario/question + + Returns: + Token that can be used to reset the scenario ID (for cleanup) + """ + token = _current_scenario_id.set(scenario_id) + if scenario_id not in _GLOBAL_INTENT_REGISTRY: + _GLOBAL_INTENT_REGISTRY[scenario_id] = [] + logger.debug("Set current scenario ID to: %s", scenario_id) + return token + + +def get_current_scenario_id() -> str: + """Get the current scenario ID for this async context. + + Returns: + The current scenario ID, or "current" if not set + """ + return _current_scenario_id.get() + + +class ToolIntentBuffer: + """Shared buffer to store tool intent captures during agent execution. + + This is used in decision-only mode to track which tools the agent + decided to call and with what parameters, without actually executing them. + + Uses a global registry so evaluators can access intents across the codebase. + The buffer uses the current scenario ID from the contextvar (set via + set_current_scenario_id) for both recording and clearing intents. + """ + + def __init__(self) -> None: + """Initialize a tool intent buffer.""" + self.intents: list[dict[str, Any]] = [] + + def record(self, tool_name: str, parameters: dict[str, Any]) -> None: + """Record a tool intent. + + Args: + tool_name: Name of the tool the agent decided to call + parameters: Parameters the agent provided for the tool call + """ + intent = {"tool": tool_name, "parameters": parameters} + self.intents.append(intent) + + current_scenario = get_current_scenario_id() + if current_scenario not in _GLOBAL_INTENT_REGISTRY: + _GLOBAL_INTENT_REGISTRY[current_scenario] = [] + _GLOBAL_INTENT_REGISTRY[current_scenario].append(intent) + + logger.debug("Recorded tool intent: %s (scenario: %s)", tool_name, current_scenario) + + def get_intents(self) -> list[dict[str, Any]]: + """Get all recorded tool intents. + + Returns: + List of tool intents with format [{"tool": "name", "parameters": {...}}] + """ + return self.intents.copy() + + def clear(self) -> None: + """Clear all recorded intents for the current scenario.""" + self.intents.clear() + current_scenario = get_current_scenario_id() + _GLOBAL_INTENT_REGISTRY[current_scenario] = [] + logger.debug("Cleared tool intent buffer for scenario %s", current_scenario) + + +def get_global_intents(scenario_id: str = "current") -> list[dict[str, Any]]: + """Retrieve tool intents from the global registry. + + This allows evaluators to access intents without needing builder access. + + Args: + scenario_id: Identifier for the scenario + + Returns: + List of tool intents + """ + return _GLOBAL_INTENT_REGISTRY.get(scenario_id, []).copy() + + +def clear_global_intents(scenario_id: str = "current") -> None: + """Clear intents from global registry. + + Args: + scenario_id: Identifier for the scenario to clear + """ + if scenario_id in _GLOBAL_INTENT_REGISTRY: + _GLOBAL_INTENT_REGISTRY[scenario_id] = [] + logger.debug("Cleared global intents for scenario %s", scenario_id) + + +class PermissiveToolInput(BaseModel): + """Input schema that accepts tool parameters as either dict or JSON string. + + This handles the case where LangChain sometimes serializes tool inputs + as JSON strings before passing them to the tool, while NAT expects dicts. + """ + + input_params: dict[str, Any] | str + + @field_validator('input_params', mode='before') + @classmethod + def parse_string_to_dict(cls, v: Any) -> dict[str, Any]: + """Convert JSON string to dict if needed.""" + if isinstance(v, str): + try: + normalized = v.replace("'", '"') + return json.loads(normalized) + except json.JSONDecodeError: + logger.warning("Failed to parse input_params string as JSON: %s", v[:100]) + return {} + elif isinstance(v, dict): + return v + else: + logger.warning("Unexpected input_params type: %s", type(v)) + return {} + + +def create_tool_stub_function( + tool_schema: dict[str, Any], + intent_buffer: ToolIntentBuffer, + canned_response: str | None = None, +) -> tuple[callable, BaseModel | None, str]: + """Create a stub function for a tool that captures intent without executing. + + Args: + tool_schema: Tool schema from the dataset (includes title, description, properties, required) + intent_buffer: Shared buffer to record tool intents + canned_response: Optional canned response to return (defaults to success message) + + Returns: + Tuple of (async_function, input_schema, function_description) + """ + tool_name = tool_schema.get("title", "unknown_tool") + tool_description = tool_schema.get("description", "") + + if canned_response is None: + response_schema = tool_schema.get("response_schema", {}) + if response_schema: + canned_response = json.dumps(_generate_mock_response(response_schema), indent=2) + else: + canned_response = f"Successfully executed {tool_name}. Operation completed." + + async def tool_stub_fn(input_params: object) -> str: + """Tool stub that captures intent without executing.""" + if isinstance(input_params, dict): + if 'params' in input_params and isinstance(input_params['params'], dict): + params_dict = input_params['params'] + else: + params_dict = input_params + else: + logger.warning("input_params is not a dict: %s", type(input_params)) + params_dict = {} + + if isinstance(params_dict, dict): + params_dict = {k: v for k, v in params_dict.items() if v is not None} + intent_buffer.record(tool_name, params_dict) + logger.info("Tool stub executed: %s with %d parameters", tool_name, len(params_dict)) + return canned_response + + tool_stub_fn.__name__ = tool_name + tool_stub_fn.__doc__ = tool_description + + return tool_stub_fn, PermissiveToolInput, tool_description + + +def _generate_mock_response(response_schema: dict[str, Any]) -> dict[str, Any]: + """Generate a mock response based on the response schema. + + Args: + response_schema: Response schema from the tool definition + + Returns: + Dictionary with mock values matching the schema + """ + mock_values: dict[str, Any] = { + "string": lambda name: f"mock_{name}", + "integer": lambda _: 100, + "number": lambda _: 100.50, + "boolean": lambda _: True, + "array": lambda _: [], + "object": lambda _: {}, + } + + mock_response = {} + for prop_name, prop_info in response_schema.get("properties", {}).items(): + prop_type = prop_info.get("type", "string") + factory = mock_values.get(prop_type) + mock_response[prop_name] = factory(prop_name) if factory else None + + return mock_response diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py index 49313c5944..b574130d13 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/config.py @@ -12,16 +12,30 @@ # 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. +"""Configuration types for the ToolTalk benchmark.""" from collections.abc import Callable +from enum import StrEnum from pydantic import Field +from pydantic import PositiveInt from nat.data_models.agent import AgentBaseConfig from nat.data_models.dataset_handler import EvalDatasetBaseConfig from nat.data_models.evaluator import EvaluatorBaseConfig +class ToolTalkApiMode(StrEnum): + """Controls which API docs are included in the tool schemas for the LLM.""" + + EXACT = "exact" + """Only APIs explicitly used in the conversation.""" + SUITE = "suite" + """All APIs from the suites used in the conversation.""" + ALL = "all" + """All available ToolTalk APIs.""" + + class ToolTalkDatasetConfig(EvalDatasetBaseConfig, name="tooltalk"): """Dataset config for ToolTalk benchmark. @@ -34,6 +48,7 @@ class ToolTalkDatasetConfig(EvalDatasetBaseConfig, name="tooltalk"): def parser(self) -> tuple[Callable, dict]: from .dataset import load_tooltalk_dataset + return load_tooltalk_dataset, {} @@ -44,9 +59,9 @@ class ToolTalkWorkflowConfig(AgentBaseConfig, name="tooltalk_workflow"): """ description: str = Field(default="ToolTalk Benchmark Workflow") - database_dir: str = Field(description="Path to ToolTalk database directory", ) - api_mode: str = Field( - default="all", + database_dir: str = Field(description="Path to ToolTalk database directory") + api_mode: ToolTalkApiMode = Field( + default=ToolTalkApiMode.ALL, description="Which API docs to include: 'exact' (only APIs in conversation), " "'suite' (all APIs in used suites), or 'all'", ) @@ -54,7 +69,7 @@ class ToolTalkWorkflowConfig(AgentBaseConfig, name="tooltalk_workflow"): default=False, description="If True, send empty descriptions in tool schemas", ) - max_tool_calls_per_turn: int = Field( + max_tool_calls_per_turn: PositiveInt = Field( default=10, description="Maximum tool calls per assistant turn before forcing a text response", ) @@ -66,4 +81,4 @@ class ToolTalkEvaluatorConfig(EvaluatorBaseConfig, name="tooltalk_evaluator"): Uses ToolTalk's built-in metrics: recall, action_precision, bad_action_rate, success. """ - database_dir: str = Field(description="Path to ToolTalk database directory", ) + database_dir: str = Field(description="Path to ToolTalk database directory") diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py index 076b61420e..3bf6b013fd 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/evaluator.py @@ -20,6 +20,7 @@ import json import logging +from functools import partial from nat.builder.builder import EvalBuilder from nat.builder.evaluator import EvaluatorInfo @@ -29,52 +30,16 @@ from nat.data_models.evaluator import EvalOutput from nat.data_models.evaluator import EvalOutputItem +from ..common.eval_helpers import run_evaluator_loop from .config import ToolTalkEvaluatorConfig logger = logging.getLogger(__name__) -@register_evaluator(config_type=ToolTalkEvaluatorConfig) -async def tooltalk_evaluator_function(config: ToolTalkEvaluatorConfig, builder: EvalBuilder): - - async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: - eval_output_items = [] - - for item in eval_input.eval_input_items: - try: - output_item = _evaluate_single(item, config.database_dir) - eval_output_items.append(output_item) - except Exception as e: - logger.exception("Error evaluating ToolTalk item %s: %s", item.id, e) - eval_output_items.append(EvalOutputItem( - id=item.id, - score=0.0, - reasoning={"error": str(e)}, - )) - - scores = [item.score for item in eval_output_items if isinstance(item.score, (int, float))] - average_score = sum(scores) / len(scores) if scores else 0.0 - - logger.info( - "ToolTalk evaluation complete: average_success=%.3f across %d conversations", - average_score, - len(scores), - ) - - return EvalOutput(average_score=average_score, eval_output_items=eval_output_items) - - yield EvaluatorInfo( - config=config, - evaluate_fn=evaluate_fn, - description="ToolTalk benchmark evaluator (recall, action_precision, success)", - ) - - def _evaluate_single(item: EvalInputItem, database_dir: str) -> EvalOutputItem: """Evaluate a single ToolTalk conversation using ToolTalk's built-in metrics.""" from tooltalk.evaluation.tool_executor import ToolExecutor - # output_obj contains the conversation JSON with predictions added by the workflow if not item.output_obj: return EvalOutputItem( id=item.id, @@ -91,7 +56,6 @@ def _evaluate_single(item: EvalInputItem, database_dir: str) -> EvalOutputItem: reasoning={"error": f"Invalid JSON in output_obj: {e}"}, ) - # Use ToolTalk's ToolExecutor to compute metrics tool_executor = ToolExecutor(init_database_dir=database_dir) result = tool_executor.evaluate_predictions(conversation_with_predictions) metrics = result.get("metrics", {}) @@ -112,3 +76,22 @@ def _evaluate_single(item: EvalInputItem, database_dir: str) -> EvalOutputItem: } return EvalOutputItem(id=item.id, score=success, reasoning=reasoning) + + +@register_evaluator(config_type=ToolTalkEvaluatorConfig) +async def tooltalk_evaluator_function(config: ToolTalkEvaluatorConfig, builder: EvalBuilder): + """Register the ToolTalk benchmark evaluator.""" + + async def evaluate_fn(eval_input: EvalInput) -> EvalOutput: + """Evaluate all items using ToolTalk's built-in metrics.""" + return run_evaluator_loop( + eval_input, + evaluate_item_fn=partial(_evaluate_single, database_dir=config.database_dir), + benchmark_name="ToolTalk", + ) + + yield EvaluatorInfo( + config=config, + evaluate_fn=evaluate_fn, + description="ToolTalk benchmark evaluator (recall, action_precision, success)", + ) diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py index 5f544e9db7..3cac17337b 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/tooltalk/workflow.py @@ -26,6 +26,7 @@ from nat.builder.function_info import FunctionInfo from nat.cli.register_workflow import register_function +from .config import ToolTalkApiMode from .config import ToolTalkWorkflowConfig logger = logging.getLogger(__name__) @@ -97,6 +98,7 @@ def _build_messages(conversation_history: list[dict], metadata: dict | None = No @register_function(config_type=ToolTalkWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def tooltalk_workflow(config: ToolTalkWorkflowConfig, builder: Builder): + """Register the ToolTalk benchmark workflow.""" from langchain_core.messages import AIMessage from langchain_core.messages import HumanMessage from langchain_core.messages import SystemMessage @@ -115,9 +117,9 @@ async def _run_conversation(input_json: str) -> str: user_data = conversation.get("user") # Select APIs based on api_mode - if config.api_mode == "exact": + if config.api_mode == ToolTalkApiMode.EXACT: apis_used = [APIS_BY_NAME[name] for name in conversation["apis_used"]] - elif config.api_mode == "suite": + elif config.api_mode == ToolTalkApiMode.SUITE: apis_used = [api for suite_name in conversation["suites_used"] for api in SUITES_BY_NAME[suite_name].apis] else: apis_used = ALL_APIS diff --git a/packages/nvidia_nat_benchmarks/tests/common/__init__.py b/packages/nvidia_nat_benchmarks/tests/common/__init__.py new file mode 100644 index 0000000000..bcd923c929 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/common/__init__.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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/packages/nvidia_nat_benchmarks/tests/common/test_bfcl_helpers.py b/packages/nvidia_nat_benchmarks/tests/common/test_bfcl_helpers.py new file mode 100644 index 0000000000..8488be1ee0 --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/common/test_bfcl_helpers.py @@ -0,0 +1,258 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Tests for common.bfcl_helpers — shared BFCL workflow utilities.""" + +from nat.plugins.benchmarks.common.bfcl_helpers import GORILLA_TO_OPENAPI +from nat.plugins.benchmarks.common.bfcl_helpers import convert_bfcl_schema_to_openai +from nat.plugins.benchmarks.common.bfcl_helpers import extract_user_message +from nat.plugins.benchmarks.common.bfcl_helpers import format_tool_calls_as_bfcl + + +class TestExtractUserMessage: + """Tests for extract_user_message.""" + + def test_single_turn_single_message(self): + turns = [[{"role": "user", "content": "What is the weather?"}]] + assert extract_user_message(turns) == "What is the weather?" + + def test_multi_turn_returns_last_user(self): + turns = [ + [{ + "role": "user", "content": "First question" + }], + [{ + "role": "user", "content": "Second question" + }], + ] + assert extract_user_message(turns) == "Second question" + + def test_mixed_roles_returns_last_user(self): + turns = [[ + { + "role": "system", "content": "You are helpful" + }, + { + "role": "user", "content": "Hello" + }, + { + "role": "assistant", "content": "Hi there" + }, + { + "role": "user", "content": "What time is it?" + }, + ]] + assert extract_user_message(turns) == "What time is it?" + + def test_no_user_message_returns_empty(self): + turns = [[{"role": "system", "content": "You are a bot"}]] + assert extract_user_message(turns) == "" + + def test_empty_turns(self): + assert extract_user_message([]) == "" + assert extract_user_message([[]]) == "" + + def test_nested_empty(self): + turns = [[], [{"role": "user", "content": "Found it"}]] + assert extract_user_message(turns) == "Found it" + + +class TestConvertBfclSchemaToOpenai: + """Tests for convert_bfcl_schema_to_openai.""" + + def test_basic_schema(self): + func = { + "name": "get_weather", + "description": "Get the weather", + "parameters": { + "properties": { + "city": { + "type": "string", "description": "City name" + }, + }, + "required": ["city"], + }, + } + result = convert_bfcl_schema_to_openai(func) + + assert result["type"] == "function" + assert result["function"]["name"] == "get_weather" + assert result["function"]["description"] == "Get the weather" + assert result["function"]["parameters"]["type"] == "object" + assert result["function"]["parameters"]["properties"]["city"]["type"] == "string" + assert result["function"]["parameters"]["required"] == ["city"] + + def test_gorilla_type_mapping(self): + """BFCL-specific types like 'float', 'dict', 'int' are mapped to OpenAPI types.""" + func = { + "name": "calculate", + "parameters": { + "properties": { + "value": { + "type": "float" + }, + "config": { + "type": "dict" + }, + "count": { + "type": "int" + }, + "items": { + "type": "tuple" + }, + }, + "required": [], + }, + } + result = convert_bfcl_schema_to_openai(func) + props = result["function"]["parameters"]["properties"] + + assert props["value"]["type"] == "number" + assert props["config"]["type"] == "object" + assert props["count"]["type"] == "integer" + assert props["items"]["type"] == "array" + + def test_unknown_type_preserved(self): + """Types not in GORILLA_TO_OPENAPI are passed through.""" + func = { + "name": "fn", + "parameters": { + "properties": { + "x": { + "type": "custom_type" + } + }, + "required": [], + }, + } + result = convert_bfcl_schema_to_openai(func) + assert result["function"]["parameters"]["properties"]["x"]["type"] == "custom_type" + + def test_missing_fields_have_defaults(self): + """Missing description and required default to empty.""" + func = {"name": "fn", "parameters": {"properties": {}}} + result = convert_bfcl_schema_to_openai(func) + + assert result["function"]["description"] == "" + assert result["function"]["parameters"]["required"] == [] + assert result["function"]["parameters"]["properties"] == {} + + def test_no_parameters_key(self): + """Function with no parameters key at all.""" + func = {"name": "noop"} + result = convert_bfcl_schema_to_openai(func) + + assert result["function"]["name"] == "noop" + assert result["function"]["parameters"]["properties"] == {} + + def test_preserves_extra_property_fields(self): + """Extra fields like 'description' and 'enum' on properties are preserved.""" + func = { + "name": "fn", + "parameters": { + "properties": { + "color": { + "type": "string", + "description": "The color", + "enum": ["red", "blue"], + }, + }, + "required": ["color"], + }, + } + result = convert_bfcl_schema_to_openai(func) + color_prop = result["function"]["parameters"]["properties"]["color"] + + assert color_prop["type"] == "string" + assert color_prop["description"] == "The color" + assert color_prop["enum"] == ["red", "blue"] + + +class TestFormatToolCallsAsBfcl: + """Tests for format_tool_calls_as_bfcl.""" + + def test_single_call_with_name_args(self): + calls = [{"name": "get_weather", "args": {"city": "SF"}}] + result = format_tool_calls_as_bfcl(calls) + assert result == "[get_weather(city='SF')]" + + def test_single_call_with_tool_parameters(self): + """Also works with 'tool'/'parameters' keys (intent format).""" + calls = [{"tool": "get_weather", "parameters": {"city": "SF"}}] + result = format_tool_calls_as_bfcl(calls) + assert result == "[get_weather(city='SF')]" + + def test_multiple_calls(self): + calls = [ + { + "name": "fn_a", "args": { + "x": 1 + } + }, + { + "name": "fn_b", "args": { + "y": "hello" + } + }, + ] + result = format_tool_calls_as_bfcl(calls) + assert result == "[fn_a(x=1), fn_b(y='hello')]" + + def test_no_args(self): + calls = [{"name": "noop", "args": {}}] + result = format_tool_calls_as_bfcl(calls) + assert result == "[noop()]" + + def test_empty_list(self): + assert format_tool_calls_as_bfcl([]) == "" + + def test_multiple_params(self): + calls = [{"name": "search", "args": {"query": "test", "limit": 10, "exact": True}}] + result = format_tool_calls_as_bfcl(calls) + assert "search(" in result + assert "query='test'" in result + assert "limit=10" in result + assert "exact=True" in result + + def test_nested_values(self): + """Nested dicts/lists use repr formatting.""" + calls = [{"name": "fn", "args": {"data": [1, 2, 3]}}] + result = format_tool_calls_as_bfcl(calls) + assert result == "[fn(data=[1, 2, 3])]" + + +class TestGorillaToOpenapi: + """Tests for the GORILLA_TO_OPENAPI mapping.""" + + def test_all_gorilla_types_mapped(self): + expected = { + "integer": "integer", + "number": "number", + "float": "number", + "string": "string", + "boolean": "boolean", + "array": "array", + "dict": "object", + "object": "object", + "tuple": "array", + "any": "string", + "String": "string", + "int": "integer", + } + assert GORILLA_TO_OPENAPI == expected + + def test_standard_types_are_identity(self): + """Standard JSON Schema types map to themselves.""" + for t in ("integer", "number", "string", "boolean", "array", "object"): + assert GORILLA_TO_OPENAPI[t] == t diff --git a/packages/nvidia_nat_benchmarks/tests/common/test_config_enums.py b/packages/nvidia_nat_benchmarks/tests/common/test_config_enums.py new file mode 100644 index 0000000000..84bb5854ed --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/common/test_config_enums.py @@ -0,0 +1,222 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Tests for config enum validation across all benchmarks. + +Verifies that StrEnum fields reject invalid values and accept valid ones, +and that configs with validators enforce their constraints. +""" + +import pytest +from pydantic import ValidationError + +from nat.plugins.benchmarks.agent_leaderboard.config import AgentLeaderboardDatasetConfig +from nat.plugins.benchmarks.agent_leaderboard.config import AgentLeaderboardDomain +from nat.plugins.benchmarks.agent_leaderboard.config import TSQEvaluatorConfig +from nat.plugins.benchmarks.bfcl.config import BFCLDatasetConfig +from nat.plugins.benchmarks.bfcl.config import BFCLEvaluatorConfig +from nat.plugins.benchmarks.bfcl.config import BFCLTestCategory +from nat.plugins.benchmarks.tooltalk.config import ToolTalkApiMode +from nat.plugins.benchmarks.tooltalk.config import ToolTalkWorkflowConfig + + +class TestToolTalkApiMode: + """Tests for ToolTalkApiMode enum.""" + + def test_valid_values(self): + assert ToolTalkApiMode.EXACT == "exact" + assert ToolTalkApiMode.SUITE == "suite" + assert ToolTalkApiMode.ALL == "all" + + def test_config_accepts_valid_string(self): + config = ToolTalkWorkflowConfig( + llm_name="test_llm", + database_dir="/tmp/db", + api_mode="exact", + ) + assert config.api_mode == ToolTalkApiMode.EXACT + + def test_config_accepts_enum_value(self): + config = ToolTalkWorkflowConfig( + llm_name="test_llm", + database_dir="/tmp/db", + api_mode=ToolTalkApiMode.SUITE, + ) + assert config.api_mode == ToolTalkApiMode.SUITE + + def test_config_rejects_invalid_value(self): + with pytest.raises(ValidationError, match="api_mode"): + ToolTalkWorkflowConfig( + llm_name="test_llm", + database_dir="/tmp/db", + api_mode="invalid_mode", + ) + + def test_default_is_all(self): + config = ToolTalkWorkflowConfig( + llm_name="test_llm", + database_dir="/tmp/db", + ) + assert config.api_mode == ToolTalkApiMode.ALL + + +class TestBFCLTestCategory: + """Tests for BFCLTestCategory enum.""" + + def test_all_categories_exist(self): + expected = [ + "simple", + "multiple", + "parallel", + "parallel_multiple", + "java", + "javascript", + "live_simple", + "live_multiple", + "live_parallel", + "live_parallel_multiple", + "irrelevance", + "live_irrelevance", + "live_relevance", + ] + assert sorted(BFCLTestCategory) == sorted(expected) + + def test_dataset_config_accepts_valid(self): + config = BFCLDatasetConfig( + file_path="/tmp/data.json", + test_category="parallel_multiple", + ) + assert config.test_category == BFCLTestCategory.PARALLEL_MULTIPLE + + def test_dataset_config_rejects_invalid(self): + with pytest.raises(ValidationError, match="test_category"): + BFCLDatasetConfig( + file_path="/tmp/data.json", + test_category="nonexistent_category", + ) + + def test_evaluator_config_accepts_valid(self): + config = BFCLEvaluatorConfig(test_category="irrelevance", language="Python") + assert config.test_category == BFCLTestCategory.IRRELEVANCE + + def test_evaluator_config_default(self): + config = BFCLEvaluatorConfig() + assert config.test_category == BFCLTestCategory.SIMPLE + assert config.language == "Python" + + +class TestBFCLLanguage: + """Tests for BFCLEvaluatorConfig language field (Literal type).""" + + def test_valid_languages(self): + for lang in ("Python", "Java", "JavaScript"): + config = BFCLEvaluatorConfig(language=lang) + assert config.language == lang + + def test_rejects_invalid_language(self): + with pytest.raises(ValidationError): + BFCLEvaluatorConfig(language="Ruby") + + def test_rejects_lowercase(self): + """Language values are case-sensitive (Literal, not StrEnum).""" + with pytest.raises(ValidationError): + BFCLEvaluatorConfig(language="python") + + +class TestAgentLeaderboardDomain: + """Tests for AgentLeaderboardDomain enum.""" + + def test_all_domains(self): + expected = {"banking", "healthcare", "insurance", "investment", "telecom"} + assert set(AgentLeaderboardDomain) == expected + + def test_config_accepts_valid_domains(self): + config = AgentLeaderboardDatasetConfig( + file_path="/tmp/data.json", + domains=["banking", "telecom"], + ) + assert config.domains == [AgentLeaderboardDomain.BANKING, AgentLeaderboardDomain.TELECOM] + + def test_config_rejects_invalid_domain(self): + with pytest.raises(ValidationError, match="domains"): + AgentLeaderboardDatasetConfig( + file_path="/tmp/data.json", + domains=["banking", "automotive"], + ) + + def test_config_rejects_empty_domains(self): + with pytest.raises(ValidationError, match="At least one domain"): + AgentLeaderboardDatasetConfig( + file_path="/tmp/data.json", + domains=[], + ) + + def test_default_is_banking(self): + config = AgentLeaderboardDatasetConfig(file_path="/tmp/data.json") + assert config.domains == [AgentLeaderboardDomain.BANKING] + + +class TestTSQEvaluatorConfigConstraints: + """Tests for TSQEvaluatorConfig weight constraints.""" + + def test_valid_weights(self): + config = TSQEvaluatorConfig(tool_weight=0.7, parameter_weight=0.3) + assert config.tool_weight == 0.7 + assert config.parameter_weight == 0.3 + + def test_rejects_negative_weight(self): + with pytest.raises(ValidationError): + TSQEvaluatorConfig(tool_weight=-0.1) + + def test_rejects_weight_over_one(self): + with pytest.raises(ValidationError): + TSQEvaluatorConfig(tool_weight=1.5) + + def test_defaults(self): + config = TSQEvaluatorConfig() + assert config.tool_weight == 1.0 + assert config.parameter_weight == 0.0 + + def test_boundary_values(self): + config = TSQEvaluatorConfig(tool_weight=0.0, parameter_weight=1.0) + assert config.tool_weight == 0.0 + assert config.parameter_weight == 1.0 + + +class TestToolTalkWorkflowConfigConstraints: + """Tests for ToolTalkWorkflowConfig PositiveInt constraints.""" + + def test_rejects_zero_max_tool_calls(self): + with pytest.raises(ValidationError): + ToolTalkWorkflowConfig( + llm_name="test", + database_dir="/tmp", + max_tool_calls_per_turn=0, + ) + + def test_rejects_negative_max_tool_calls(self): + with pytest.raises(ValidationError): + ToolTalkWorkflowConfig( + llm_name="test", + database_dir="/tmp", + max_tool_calls_per_turn=-1, + ) + + def test_accepts_positive(self): + config = ToolTalkWorkflowConfig( + llm_name="test", + database_dir="/tmp", + max_tool_calls_per_turn=5, + ) + assert config.max_tool_calls_per_turn == 5 diff --git a/packages/nvidia_nat_benchmarks/tests/common/test_eval_helpers.py b/packages/nvidia_nat_benchmarks/tests/common/test_eval_helpers.py new file mode 100644 index 0000000000..87008f273e --- /dev/null +++ b/packages/nvidia_nat_benchmarks/tests/common/test_eval_helpers.py @@ -0,0 +1,139 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. +"""Tests for common.eval_helpers — the shared evaluator loop.""" + +from nat.data_models.evaluator import EvalInput +from nat.data_models.evaluator import EvalInputItem +from nat.data_models.evaluator import EvalOutputItem +from nat.plugins.benchmarks.common.eval_helpers import run_evaluator_loop + + +def _make_item(item_id: str, output: str = "output", expected: str = "expected") -> EvalInputItem: + """Create a minimal EvalInputItem for testing.""" + return EvalInputItem( + id=item_id, + input_obj="input", + output_obj=output, + expected_output_obj=expected, + full_dataset_entry={"id": item_id}, + ) + + +class TestRunEvaluatorLoop: + """Tests for run_evaluator_loop.""" + + def test_basic_scoring(self): + """All items score 1.0 => average is 1.0.""" + items = [_make_item("a"), _make_item("b"), _make_item("c")] + eval_input = EvalInput(eval_input_items=items) + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + return EvalOutputItem(id=item.id, score=1.0, reasoning={"ok": True}) + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert result.average_score == 1.0 + assert len(result.eval_output_items) == 3 + assert all(item.score == 1.0 for item in result.eval_output_items) + + def test_mixed_scores(self): + """Average of [1.0, 0.0, 0.5] => 0.5.""" + items = [_make_item("a"), _make_item("b"), _make_item("c")] + eval_input = EvalInput(eval_input_items=items) + scores = [1.0, 0.0, 0.5] + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + idx = ["a", "b", "c"].index(item.id) + return EvalOutputItem(id=item.id, score=scores[idx], reasoning={}) + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert result.average_score == 0.5 + assert len(result.eval_output_items) == 3 + + def test_empty_input(self): + """Empty input => average 0.0, no items.""" + eval_input = EvalInput(eval_input_items=[]) + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + raise AssertionError("Should not be called") + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert result.average_score == 0.0 + assert len(result.eval_output_items) == 0 + + def test_error_handling_gives_zero_score(self): + """When evaluate_item_fn raises, that item gets score=0.0 with error in reasoning.""" + items = [_make_item("good"), _make_item("bad"), _make_item("good2")] + eval_input = EvalInput(eval_input_items=items) + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + if item.id == "bad": + raise ValueError("Scoring exploded") + return EvalOutputItem(id=item.id, score=1.0, reasoning={"ok": True}) + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert len(result.eval_output_items) == 3 + # Good items scored 1.0, bad item scored 0.0 + scores_by_id = {item.id: item.score for item in result.eval_output_items} + assert scores_by_id["good"] == 1.0 + assert scores_by_id["bad"] == 0.0 + assert scores_by_id["good2"] == 1.0 + # Average: (1.0 + 0.0 + 1.0) / 3 + assert abs(result.average_score - 2.0 / 3.0) < 1e-9 + + # Error item has error in reasoning + bad_item = next(i for i in result.eval_output_items if i.id == "bad") + assert "error" in bad_item.reasoning + assert "Scoring exploded" in bad_item.reasoning["error"] + + def test_all_errors(self): + """When all items fail, average is 0.0.""" + items = [_make_item("a"), _make_item("b")] + eval_input = EvalInput(eval_input_items=items) + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + raise RuntimeError("boom") + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert result.average_score == 0.0 + assert all(item.score == 0.0 for item in result.eval_output_items) + + def test_preserves_item_ids(self): + """Output items have the same IDs as input items, in order.""" + items = [_make_item("x"), _make_item("y"), _make_item("z")] + eval_input = EvalInput(eval_input_items=items) + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + return EvalOutputItem(id=item.id, score=0.5, reasoning={}) + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert [item.id for item in result.eval_output_items] == ["x", "y", "z"] + + def test_single_item(self): + """Single item => average equals that item's score.""" + eval_input = EvalInput(eval_input_items=[_make_item("only")]) + + def score_fn(item: EvalInputItem) -> EvalOutputItem: + return EvalOutputItem(id=item.id, score=0.75, reasoning={"f1": 0.75}) + + result = run_evaluator_loop(eval_input, score_fn, "TestBench") + + assert result.average_score == 0.75 + assert len(result.eval_output_items) == 1 From ab4c3030f110da000a157fe13d66642a8cebf330 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 16:53:48 -0700 Subject: [PATCH 06/10] vale fixes and coderabbit's legit feedback Signed-off-by: Bryan Bednarski --- .../styles/config/vocabularies/nat/accept.txt | 4 ++++ .../benchmarks/agent_leaderboard/README.md | 2 +- examples/benchmarks/bfcl/README.md | 22 ++++++++--------- examples/benchmarks/byob/README.md | 24 +++++++++---------- examples/benchmarks/tooltalk/README.md | 10 ++++---- .../configs/agent_leaderboard_eval.yaml | 15 ++++++++++++ .../configs/bfcl_ast_eval.yaml | 15 ++++++++++++ .../configs/tooltalk_eval.yaml | 15 ++++++++++++ packages/nvidia_nat_benchmarks/pyproject.toml | 4 ++-- .../benchmarks/common/tool_intent_stubs.py | 18 ++++++++++---- .../tests/agent_leaderboard/conftest.py | 14 ----------- .../tests/byob/conftest.py | 14 ----------- pyproject.toml | 8 +++++++ 13 files changed, 102 insertions(+), 63 deletions(-) delete mode 100644 packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py delete mode 100644 packages/nvidia_nat_benchmarks/tests/byob/conftest.py diff --git a/ci/vale/styles/config/vocabularies/nat/accept.txt b/ci/vale/styles/config/vocabularies/nat/accept.txt index 0dd6609491..9babca497b 100644 --- a/ci/vale/styles/config/vocabularies/nat/accept.txt +++ b/ci/vale/styles/config/vocabularies/nat/accept.txt @@ -20,6 +20,7 @@ Authlib [Bb]ackoff [Bb]ackpressure [Bb]atcher +BFCL [Bb]oolean Brev [Cc]allable(s?) @@ -55,6 +56,7 @@ Datadog [Dd]atastore DB(s?) [Dd]eclaratively +[Dd]eduplic(ate|ated|ation) [Dd]enylist [Dd]eserialize [Dd]ev @@ -181,11 +183,13 @@ SSE [Ss]ubgraph(s?) [Ss]ubpackage(s?) [Ss]ubsampl(e|ing) +[Ss]ubstring(s?) [Ss]ubtask(s?) [Ss]ubword(s?) [Ss]uperset(s?) Tavily [Tt]eardown +[Tt]elecom [Tt]imestamp(s?) [Tt]okenization [Tt]oolchain diff --git a/examples/benchmarks/agent_leaderboard/README.md b/examples/benchmarks/agent_leaderboard/README.md index 0c0cdf6a0b..21ef4f71a1 100644 --- a/examples/benchmarks/agent_leaderboard/README.md +++ b/examples/benchmarks/agent_leaderboard/README.md @@ -19,7 +19,7 @@ limitations under the License. **Complexity:** 🟡 Intermediate -Evaluate NAT agent workflows against the [Galileo Agent Leaderboard v2](https://huggingface.co/datasets/galileo-ai/agent-leaderboard-v2) benchmark. This benchmark tests whether an agent can select the correct tools for real-world use cases across multiple domains. +Evaluate NeMo Agent Toolkit agent workflows against the [Galileo Agent Leaderboard v2](https://huggingface.co/datasets/galileo-ai/agent-leaderboard-v2) benchmark. This benchmark tests whether an agent can select the correct tools for real-world use cases across multiple domains. ## Key Features diff --git a/examples/benchmarks/bfcl/README.md b/examples/benchmarks/bfcl/README.md index 23300d3531..36dbdd9b56 100644 --- a/examples/benchmarks/bfcl/README.md +++ b/examples/benchmarks/bfcl/README.md @@ -19,9 +19,9 @@ limitations under the License. **Complexity:** 🟡 Intermediate -Evaluate NAT agent workflows against the [Berkeley Function Calling Leaderboard (BFCL)](https://gorilla.cs.berkeley.edu/leaderboard.html) v3 benchmark. BFCL tests single-turn function calling accuracy across simple, parallel, and multiple function call scenarios. +Evaluate NeMo Agent Toolkit agent workflows against the [Berkeley Function Calling Leaderboard (BFCL)](https://gorilla.cs.berkeley.edu/leaderboard.html) v3 benchmark. BFCL tests single-turn function calling accuracy across simple, parallel, and multiple function call scenarios. -This example supports **three evaluation modes** that demonstrate different NAT integration patterns: +This example supports **three evaluation modes** that demonstrate different NeMo Agent Toolkit integration patterns: | Mode | Workflow Type | How it works | |------|--------------|--------------| @@ -51,13 +51,13 @@ uv pip install -e examples/benchmarks/bfcl The NVIDIA `nvidia-bfcl` package must be installed (includes datasets and AST checker). Due to an overly restrictive `numpy==1.26.4` pin in `nvidia-bfcl` that conflicts with -NAT's `numpy>=2.3`, install it with `--no-deps`: +NeMo Agent Toolkit's `numpy>=2.3`, install it with `--no-deps`: ```bash uv pip install nvidia-bfcl --no-deps ``` -> `nvidia-bfcl` works correctly with numpy 2.x at runtime — the pin is a packaging +> `nvidia-bfcl` works correctly with NumPy 2.x at runtime — the pin is a packaging > constraint only. The `[bfcl]` extra in `nvidia-nat-benchmarks` installs the required > `tree-sitter` dependencies automatically. @@ -71,7 +71,7 @@ uv pip install nvidia-bfcl --no-deps export NVIDIA_API_KEY= ``` -Or add it to a `.env` file in your project root (NAT loads `.env` automatically). +Or add it to a `.env` file in your project root (NeMo Agent Toolkit loads `.env` automatically). ### 2. Locate the BFCL dataset @@ -167,7 +167,7 @@ INFO - BFCL evaluation complete: accuracy=0.850 (85/100) category=simple | bfcl | 0.850 | bfcl_output.json | ``` -> The system prompt uses BFCL's standard format instruction which constrains the LLM to output +> The system prompt uses the standard BFCL format instruction which constrains the LLM to output > `[func_name(param=value)]` format. Accuracy varies by model — `llama-3.3-70b-instruct` > typically scores 80-95% on the simple split. @@ -175,7 +175,7 @@ INFO - BFCL evaluation complete: accuracy=0.850 (85/100) category=simple ## Evaluation Mode 2: Native Function Calling -Uses `llm.bind_tools(schemas)` — the LLM makes structured tool calls via the native `tools=` API parameter. Tool call args are extracted from `AIMessage.tool_calls` and formatted for BFCL scoring. +Uses `llm.bind_tools(schemas)` — the LLM makes structured tool calls via the native `tools=` API parameter. Tool call arguments are extracted from `AIMessage.tool_calls` and formatted for BFCL scoring. ```bash nat eval --config_file examples/benchmarks/bfcl/configs/eval_fc_simple.yml @@ -195,7 +195,7 @@ INFO - BFCL evaluation complete: accuracy=0.720 (288/400) category=simple | bfcl | 0.720 | bfcl_output.json | ``` -> FC mode converts BFCL's function schemas to OpenAI tool format and uses `bind_tools()`. +> FC mode converts BFCL function schemas to OpenAI tool format and uses `bind_tools()`. > The LLM returns structured `tool_calls` with typed arguments, but accuracy can be lower > than AST prompting when the schema type conversion (BFCL types → OpenAPI types) loses > precision or the model returns string values where integers are expected. @@ -235,10 +235,10 @@ INFO - BFCL evaluation complete: accuracy=0.900 (360/400) category=simple ### The `bfcl_evaluator` -All three evaluation modes use the same evaluator: **`bfcl_evaluator`** (`_type: bfcl_evaluator` in the eval config). It calls BFCL's `ast_checker()` function directly in Python to validate the model's function call output against the ground-truth possible answers. The evaluator handles three steps: +All three evaluation modes use the same evaluator: **`bfcl_evaluator`** (`_type: bfcl_evaluator` in the eval config). It calls the BFCL `ast_checker()` function directly in Python to validate the model's function call output against the ground-truth possible answers. The evaluator handles three steps: 1. **Extract** the function call from the model's raw output (strips markdown, prose, JSON wrapping) -2. **Decode** the extracted text into a structured function call via BFCL's `default_decode_ast_prompting()` +2. **Decode** the extracted text into a structured function call via the BFCL `default_decode_ast_prompting()` utility 3. **Check** the decoded call against ground truth via `ast_checker()` — validates function name, parameter names, types, and values The evaluator is configured in the YAML under `eval.evaluators`: @@ -289,7 +289,7 @@ Accuracy: 0.850 ### Score interpretation - **1.0**: Function name, parameter names, types, and values all match ground truth -- **0.0**: Any mismatch — wrong function, wrong params, wrong types, or unparseable output +- **0.0**: Any mismatch — wrong function, wrong parameters, wrong types, or output that cannot be parsed --- diff --git a/examples/benchmarks/byob/README.md b/examples/benchmarks/byob/README.md index 19088e4b92..cc489154e8 100644 --- a/examples/benchmarks/byob/README.md +++ b/examples/benchmarks/byob/README.md @@ -19,17 +19,17 @@ limitations under the License. **Complexity:** 🟡 Intermediate -Run [NeMo Evaluator BYOB](https://docs.nvidia.com/nemo/evaluator/latest/) benchmarks directly on NAT agent workflows — without re-implementing the dataset loader or scorer logic. +Run [NeMo Evaluator BYOB](https://docs.nvidia.com/nemo/evaluator/latest/) benchmarks directly on NeMo Agent Toolkit workflows — without re-implementing the dataset loader or scorer logic. -## Why BYOB in NAT? +## Why BYOB in NeMo Agent Toolkit? -NeMo Evaluator's BYOB (Bring Your Own Benchmark) framework lets users define custom evaluation benchmarks using the `@benchmark` and `@scorer` decorators. A benchmark definition specifies a dataset, a prompt template, and a scorer function — everything needed to evaluate a model. +The NeMo Evaluator BYOB (Bring Your Own Benchmark) framework lets users define custom evaluation benchmarks using the `@benchmark` and `@scorer` decorators. A benchmark definition specifies a dataset, a prompt template, and a scorer function — everything needed to evaluate a model. -Normally, NeMo Evaluator runs the full pipeline: it loads the dataset, renders prompts, calls the model endpoint, and scores the responses. **This integration reuses the benchmark definition, dataset loading, and scorer functions from NeMo Evaluator, but replaces the model-calling step with NAT's workflow execution.** This means: +Normally, NeMo Evaluator runs the full pipeline: it loads the dataset, renders prompts, calls the model endpoint, and scores the responses. **This integration reuses the benchmark definition, dataset loading, and scorer functions from NeMo Evaluator, but replaces the model-calling step with NeMo Agent Toolkit workflow execution.** This means: -- **Existing BYOB benchmarks work as-is** — the same `@benchmark` + `@scorer` Python file you use with NeMo Evaluator works identically with NAT. No re-implementation needed. -- **NAT handles the agent execution** — instead of calling a model endpoint, NAT runs its own workflow (tool-calling agents, RAG pipelines, multi-step reasoning chains) to generate responses. -- **Scorers run in-process** — the scorer receives `ScorerInput(response=workflow_output, target=ground_truth)` and returns a score dict. `model_call_fn` is `None` (NAT handles all LLM calls upstream). +- **Existing BYOB benchmarks work as-is** — the same `@benchmark` + `@scorer` Python file you use with NeMo Evaluator works identically with NeMo Agent Toolkit. No re-implementation needed. +- **NeMo Agent Toolkit handles the agent execution** — instead of calling a model endpoint, the toolkit runs its own workflow (tool-calling agents, RAG pipelines, multi-step reasoning chains) to generate responses. +- **Scorers run in-process** — the scorer receives `ScorerInput(response=workflow_output, target=ground_truth)` and returns a score dict. `model_call_fn` is `None` (NeMo Agent Toolkit handles all LLM calls upstream). ``` ┌─────────────────────────────────────┐ @@ -51,8 +51,8 @@ Normally, NeMo Evaluator runs the full pipeline: it loads the dataset, renders p - **Direct reuse**: Any benchmark defined with `@benchmark` + `@scorer` works without modification - **Built-in scorers**: `exact_match`, `contains`, `f1_token`, `bleu`, `rouge`, `regex_match` — all from `nemo_evaluator.contrib.byob.scorers` - **Custom scorers**: Write your own scorer function with `ScorerInput` -- **HuggingFace datasets**: BYOB's `load_dataset()` supports `hf://` URIs, local JSONL, CSV, and TSV -- **Dataset from benchmark**: Dataset path, prompt template, and target field come from the benchmark definition — no duplication in NAT config +- **HuggingFace datasets**: The BYOB `load_dataset()` function supports `hf://` URIs, local JSONL, CSV, and TSV +- **Dataset from benchmark**: Dataset path, prompt template, and target field come from the benchmark definition — no duplication in the eval config ## Table of Contents @@ -197,7 +197,7 @@ Average score: 0.667 ## Built-in Scorers Reference -BYOB scorers come from the [NeMo Evaluator](https://docs.nvidia.com/nemo/evaluator/latest/) framework (`nemo_evaluator.contrib.byob.scorers`). They are standard NLP evaluation metrics packaged as simple Python functions that accept a `ScorerInput` and return a dict of metric values. When you use BYOB through NAT, the scorer runs in-process against the workflow's output — NAT handles the LLM calls and the scorer only sees the final `(response, target)` pair. +BYOB scorers come from the [NeMo Evaluator](https://docs.nvidia.com/nemo/evaluator/latest/) framework (`nemo_evaluator.contrib.byob.scorers`). They are standard NLP evaluation metrics packaged as simple Python functions that accept a `ScorerInput` and return a dict of metric values. When you use BYOB through NeMo Agent Toolkit, the scorer runs in-process against the workflow output — the toolkit handles the LLM calls and the scorer only sees the final `(response, target)` pair. You can use any built-in scorer directly, compose them with `any_of()` / `all_of()`, or write your own from scratch. The only requirement is the signature: `def scorer(sample: ScorerInput) -> dict`. @@ -240,7 +240,7 @@ def flexible_scorer(sample: ScorerInput) -> dict: ### Configuring `score_field` -Set `score_field` in the evaluator config to tell NAT which key from the scorer output dict to use as the primary score: +Set `score_field` in the evaluator config to select which key from the scorer output dict to use as the primary score: ```yaml evaluators: @@ -289,5 +289,5 @@ def custom_scorer(sample: ScorerInput) -> dict: | `response` | `str` | Model's generated response | | `target` | `Any` | Ground-truth value from dataset | | `metadata` | `dict` | Full dataset row | -| `model_call_fn` | `Optional[Callable]` | Always `None` in NAT (LLM calls handled by workflow) | +| `model_call_fn` | `Optional[Callable]` | Always `None` in NeMo Agent Toolkit (LLM calls handled by workflow) | | `config` | `Dict[str, Any]` | Benchmark's `extra` config | diff --git a/examples/benchmarks/tooltalk/README.md b/examples/benchmarks/tooltalk/README.md index 536efae89f..17bf44ef04 100644 --- a/examples/benchmarks/tooltalk/README.md +++ b/examples/benchmarks/tooltalk/README.md @@ -19,13 +19,13 @@ limitations under the License. **Complexity:** 🟡 Intermediate -Evaluate NAT agent workflows against the [ToolTalk](https://github.com/microsoft/ToolTalk) multi-turn function calling benchmark. ToolTalk tests whether an agent can correctly select and execute API tools across multi-turn conversations with simulated database backends. +Evaluate NeMo Agent Toolkit agent workflows against the [ToolTalk](https://github.com/microsoft/ToolTalk) multi-turn function calling benchmark. ToolTalk tests whether an agent can correctly select and execute API tools across multi-turn conversations with simulated database backends. ## Key Features - **Multi-turn conversations**: Each scenario replays a full user-agent conversation with ground-truth tool calls - **Simulated tool backends**: ToolTalk's `ToolExecutor` provides realistic database-backed tool responses -- **Native FC via `bind_tools()`**: Uses NAT's LangChain LLM with native function calling — no raw API calls +- **Native FC via `bind_tools()`**: Uses the NeMo Agent Toolkit LangChain LLM with native function calling — no raw API calls - **Built-in metrics**: Reports `recall`, `action_precision`, `bad_action_rate`, `success`, and `soft_success` - **Easy + Full splits**: 29 easy conversations, 50 full conversations @@ -67,7 +67,7 @@ pip install nvidia-tooltalk export NVIDIA_API_KEY= ``` -Or add it to a `.env` file in your project root (NAT loads `.env` automatically). +Or add it to a `.env` file in your project root (NeMo Agent Toolkit loads `.env` automatically). ### 2. Locate ToolTalk data paths @@ -195,7 +195,7 @@ Total conversations: 29 | `action_precision` | Fraction of predicted actions that match ground truth | | `bad_action_rate` | Fraction of actions that are successful but don't match ground truth | | `success` | 1.0 only if recall=1.0 AND bad_action_rate=0.0 | -| `soft_success` | recall * (1 - bad_action_rate) — partial credit metric | +| `soft_success` | `recall * (1 - bad_action_rate)` — partial credit metric | --- @@ -213,7 +213,7 @@ Total conversations: 29 | Field | Default | Description | |-------|---------|-------------| -| `file_path` | required | Path to ToolTalk data directory (easy or tooltalk split) | +| `file_path` | required | Path to ToolTalk data directory (`easy` or `tooltalk` split) | | `database_dir` | required | Path to ToolTalk database directory | ### Tips for better results diff --git a/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml b/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml index 5bf488a6e5..b8161ee392 100644 --- a/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml +++ b/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # Agent Leaderboard v2 evaluation config for NAT # Usage: nat eval --config_file packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml # diff --git a/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml b/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml index fbd93c0471..8623a5c620 100644 --- a/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml +++ b/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # BFCL v3 AST prompting evaluation config for NAT # Usage: nat eval --config_file packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml # diff --git a/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml b/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml index e3644759c6..0284b7e3c0 100644 --- a/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml +++ b/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml @@ -1,3 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# 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. + # ToolTalk benchmark evaluation config for NAT # Usage: nat eval --config-file packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml # diff --git a/packages/nvidia_nat_benchmarks/pyproject.toml b/packages/nvidia_nat_benchmarks/pyproject.toml index 8de590a26b..d8f0779c55 100644 --- a/packages/nvidia_nat_benchmarks/pyproject.toml +++ b/packages/nvidia_nat_benchmarks/pyproject.toml @@ -59,7 +59,7 @@ dependencies = [ [tool.setuptools_dynamic_dependencies.optional-dependencies] tooltalk = [ - "nvidia-tooltalk", + "nvidia-tooltalk~=26.1", ] bfcl = [ # nvidia-bfcl must be installed separately with --no-deps due to an overly @@ -70,7 +70,7 @@ bfcl = [ "tree-sitter-javascript~=0.21.0", ] byob = [ - "nemo-evaluator", + "nemo-evaluator~=0.1", ] agent-leaderboard = [ "datasets~=4.4", diff --git a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py index 24fcbd9815..1663dcdcb5 100644 --- a/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py +++ b/packages/nvidia_nat_benchmarks/src/nat/plugins/benchmarks/common/tool_intent_stubs.py @@ -157,12 +157,22 @@ class PermissiveToolInput(BaseModel): def parse_string_to_dict(cls, v: Any) -> dict[str, Any]: """Convert JSON string to dict if needed.""" if isinstance(v, str): + # Try standard JSON first (preserves values with apostrophes like O'Reilly) try: - normalized = v.replace("'", '"') - return json.loads(normalized) + return json.loads(v) except json.JSONDecodeError: - logger.warning("Failed to parse input_params string as JSON: %s", v[:100]) - return {} + pass + # Fallback: try ast.literal_eval for Python-style dicts with single quotes + try: + import ast + + result = ast.literal_eval(v) + if isinstance(result, dict): + return result + except (ValueError, SyntaxError): + pass + logger.warning("Failed to parse input_params string as JSON (length=%d)", len(v)) + return {} elif isinstance(v, dict): return v else: diff --git a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py b/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py deleted file mode 100644 index bcd923c929..0000000000 --- a/packages/nvidia_nat_benchmarks/tests/agent_leaderboard/conftest.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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/packages/nvidia_nat_benchmarks/tests/byob/conftest.py b/packages/nvidia_nat_benchmarks/tests/byob/conftest.py deleted file mode 100644 index bcd923c929..0000000000 --- a/packages/nvidia_nat_benchmarks/tests/byob/conftest.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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/pyproject.toml b/pyproject.toml index 52de63d06a..301163cfe2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,6 +123,10 @@ examples = [ "nat_agents_examples", "nat_alert_triage_agent", "nat_autogen_demo", + "nat_benchmark_agent_leaderboard", + "nat_benchmark_bfcl", + "nat_benchmark_byob", + "nat_benchmark_tooltalk", "nat_automated_description_generation", "nat_currency_agent_a2a", "nat_dpo_tic_tac_toe", @@ -259,6 +263,10 @@ nat_agno_personal_finance = { path = "examples/frameworks/agno_personal_finance" nat_agents_examples = { path = "examples/agents", editable = true } nat_alert_triage_agent = { path = "examples/advanced_agents/alert_triage_agent", editable = true } nat_autogen_demo = { path = "examples/frameworks/nat_autogen_demo", editable = true } +nat_benchmark_agent_leaderboard = { path = "examples/benchmarks/agent_leaderboard", editable = true } +nat_benchmark_bfcl = { path = "examples/benchmarks/bfcl", editable = true } +nat_benchmark_byob = { path = "examples/benchmarks/byob", editable = true } +nat_benchmark_tooltalk = { path = "examples/benchmarks/tooltalk", editable = true } nat_automated_description_generation = { path = "examples/custom_functions/automated_description_generation", editable = true } nat_currency_agent_a2a = { path = "examples/A2A/currency_agent_a2a", editable = true } nat_dpo_tic_tac_toe = { path = "examples/finetuning/dpo_tic_tac_toe", editable = true } From 385376c7892836c35819d4408e5561a7ef1bd80d Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 20:52:09 -0700 Subject: [PATCH 07/10] add subpackage to uv.lock & pyproject Signed-off-by: Bryan Bednarski --- .pre-commit-config.yaml | 1 + packages/nvidia_nat_benchmarks/uv.lock | 4720 ++++++++++++++++++++++++ uv.lock | 515 +++ 3 files changed, 5236 insertions(+) create mode 100644 packages/nvidia_nat_benchmarks/uv.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 124420ea8f..bc610108d6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,6 +35,7 @@ repos: - { id: uv-lock, name: "uv-lock-adk", args: [--project, packages/nvidia_nat_adk], files: "packages/nvidia_nat_adk/pyproject.toml" } - { id: uv-lock, name: "uv-lock-agno", args: [--project, packages/nvidia_nat_agno], files: "packages/nvidia_nat_agno/pyproject.toml" } - { id: uv-lock, name: "uv-lock-autogen", args: [--project, packages/nvidia_nat_autogen], files: "packages/nvidia_nat_autogen/pyproject.toml" } + - { id: uv-lock, name: "uv-lock-benchmarks", args: [--project, packages/nvidia_nat_benchmarks], files: "packages/nvidia_nat_benchmarks/pyproject.toml" } - { id: uv-lock, name: "uv-lock-core", args: [--project, packages/nvidia_nat_core], files: "packages/nvidia_nat_core/pyproject.toml" } - { id: uv-lock, name: "uv-lock-crewai", args: [--project, packages/nvidia_nat_crewai], files: "packages/nvidia_nat_crewai/pyproject.toml" } - { id: uv-lock, name: "uv-lock-data_flywheel", args: [--project, packages/nvidia_nat_data_flywheel], files: "packages/nvidia_nat_data_flywheel/pyproject.toml" } diff --git a/packages/nvidia_nat_benchmarks/uv.lock b/packages/nvidia_nat_benchmarks/uv.lock new file mode 100644 index 0000000000..e14188f88d --- /dev/null +++ b/packages/nvidia_nat_benchmarks/uv.lock @@ -0,0 +1,4720 @@ +version = 1 +revision = 3 +requires-python = ">=3.11, <3.14" +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version == '3.12.*'", + "python_full_version < '3.12'", +] + +[manifest] +build-constraints = [ + { name = "setuptools", specifier = ">=64" }, + { name = "setuptools-dynamic-dependencies", specifier = ">=1.0.0" }, + { name = "setuptools-scm", specifier = ">=8" }, +] + +[[package]] +name = "aioboto3" +version = "15.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiobotocore", extra = ["boto3"] }, + { name = "aiofiles" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/01/92e9ab00f36e2899315f49eefcd5b4685fbb19016c7f19a9edf06da80bb0/aioboto3-15.5.0.tar.gz", hash = "sha256:ea8d8787d315594842fbfcf2c4dce3bac2ad61be275bc8584b2ce9a3402a6979", size = 255069, upload-time = "2025-10-30T13:37:16.122Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/3e/e8f5b665bca646d43b916763c901e00a07e40f7746c9128bdc912a089424/aioboto3-15.5.0-py3-none-any.whl", hash = "sha256:cc880c4d6a8481dd7e05da89f41c384dbd841454fc1998ae25ca9c39201437a6", size = 35913, upload-time = "2025-10-30T13:37:14.549Z" }, +] + +[[package]] +name = "aiobotocore" +version = "2.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "aioitertools" }, + { name = "botocore" }, + { name = "jmespath" }, + { name = "multidict" }, + { name = "python-dateutil" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/94/2e4ec48cf1abb89971cb2612d86f979a6240520f0a659b53a43116d344dc/aiobotocore-2.25.1.tar.gz", hash = "sha256:ea9be739bfd7ece8864f072ec99bb9ed5c7e78ebb2b0b15f29781fbe02daedbc", size = 120560, upload-time = "2025-10-28T22:33:21.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/2a/d275ec4ce5cd0096665043995a7d76f5d0524853c76a3d04656de49f8808/aiobotocore-2.25.1-py3-none-any.whl", hash = "sha256:eb6daebe3cbef5b39a0bb2a97cffbe9c7cb46b2fcc399ad141f369f3c2134b1f", size = 86039, upload-time = "2025-10-28T22:33:19.949Z" }, +] + +[package.optional-dependencies] +boto3 = [ + { name = "boto3" }, +] + +[[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.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/4c/a164164834f03924d9a29dc3acd9e7ee58f95857e0b467f6d04298594ebb/aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b", size = 746051, upload-time = "2026-01-03T17:29:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/82/71/d5c31390d18d4f58115037c432b7e0348c60f6f53b727cad33172144a112/aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64", size = 499234, upload-time = "2026-01-03T17:29:44.822Z" }, + { url = "https://files.pythonhosted.org/packages/0e/c9/741f8ac91e14b1d2e7100690425a5b2b919a87a5075406582991fb7de920/aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea", size = 494979, upload-time = "2026-01-03T17:29:46.405Z" }, + { url = "https://files.pythonhosted.org/packages/75/b5/31d4d2e802dfd59f74ed47eba48869c1c21552c586d5e81a9d0d5c2ad640/aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a", size = 1748297, upload-time = "2026-01-03T17:29:48.083Z" }, + { url = "https://files.pythonhosted.org/packages/1a/3e/eefad0ad42959f226bb79664826883f2687d602a9ae2941a18e0484a74d3/aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540", size = 1707172, upload-time = "2026-01-03T17:29:49.648Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3a/54a64299fac2891c346cdcf2aa6803f994a2e4beeaf2e5a09dcc54acc842/aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b", size = 1805405, upload-time = "2026-01-03T17:29:51.244Z" }, + { url = "https://files.pythonhosted.org/packages/6c/70/ddc1b7169cf64075e864f64595a14b147a895a868394a48f6a8031979038/aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3", size = 1899449, upload-time = "2026-01-03T17:29:53.938Z" }, + { url = "https://files.pythonhosted.org/packages/a1/7e/6815aab7d3a56610891c76ef79095677b8b5be6646aaf00f69b221765021/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1", size = 1748444, upload-time = "2026-01-03T17:29:55.484Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f2/073b145c4100da5511f457dc0f7558e99b2987cf72600d42b559db856fbc/aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3", size = 1606038, upload-time = "2026-01-03T17:29:57.179Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c1/778d011920cae03ae01424ec202c513dc69243cf2db303965615b81deeea/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440", size = 1724156, upload-time = "2026-01-03T17:29:58.914Z" }, + { url = "https://files.pythonhosted.org/packages/0e/cb/3419eabf4ec1e9ec6f242c32b689248365a1cf621891f6f0386632525494/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7", size = 1722340, upload-time = "2026-01-03T17:30:01.962Z" }, + { url = "https://files.pythonhosted.org/packages/7a/e5/76cf77bdbc435bf233c1f114edad39ed4177ccbfab7c329482b179cff4f4/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c", size = 1783041, upload-time = "2026-01-03T17:30:03.609Z" }, + { url = "https://files.pythonhosted.org/packages/9d/d4/dd1ca234c794fd29c057ce8c0566b8ef7fd6a51069de5f06fa84b9a1971c/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51", size = 1596024, upload-time = "2026-01-03T17:30:05.132Z" }, + { url = "https://files.pythonhosted.org/packages/55/58/4345b5f26661a6180afa686c473620c30a66afdf120ed3dd545bbc809e85/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4", size = 1804590, upload-time = "2026-01-03T17:30:07.135Z" }, + { url = "https://files.pythonhosted.org/packages/7b/06/05950619af6c2df7e0a431d889ba2813c9f0129cec76f663e547a5ad56f2/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29", size = 1740355, upload-time = "2026-01-03T17:30:09.083Z" }, + { url = "https://files.pythonhosted.org/packages/3e/80/958f16de79ba0422d7c1e284b2abd0c84bc03394fbe631d0a39ffa10e1eb/aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239", size = 433701, upload-time = "2026-01-03T17:30:10.869Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f2/27cdf04c9851712d6c1b99df6821a6623c3c9e55956d4b1e318c337b5a48/aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f", size = 457678, upload-time = "2026-01-03T17:30:12.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" }, + { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" }, + { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" }, + { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" }, + { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" }, + { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" }, + { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" }, + { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" }, + { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" }, + { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" }, + { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" }, + { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" }, + { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" }, + { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" }, + { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" }, + { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" }, + { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" }, + { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" }, + { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" }, + { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" }, +] + +[[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 = "aiosqlite" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" }, +] + +[[package]] +name = "alembic" +version = "1.18.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mako" }, + { name = "sqlalchemy" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725, upload-time = "2026-02-10T16:00:47.195Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893, upload-time = "2026-02-10T16:00:49.997Z" }, +] + +[[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" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + +[[package]] +name = "asgi-lifespan" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/da/e7908b54e0f8043725a990bf625f2041ecf6bfe8eb7b19407f1c00b630f7/asgi-lifespan-2.1.0.tar.gz", hash = "sha256:5e2effaf0bfe39829cf2d64e7ecc47c7d86d676a6599f7afba378c31f5e3a308", size = 15627, upload-time = "2023-03-28T17:35:49.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/f5/c36551e93acba41a59939ae6a0fb77ddb3f2e8e8caa716410c65f7341f72/asgi_lifespan-2.1.0-py3-none-any.whl", hash = "sha256:ed840706680e28428c01e14afb3875d7d76d3206f3d5b2f2294e059b5c23804f", size = 10895, upload-time = "2023-03-28T17:35:47.772Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "authlib" +version = "1.6.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "blinker" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, +] + +[[package]] +name = "boto3" +version = "1.40.61" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/f9/6ef8feb52c3cce5ec3967a535a6114b57ac7949fd166b0f3090c2b06e4e5/boto3-1.40.61.tar.gz", hash = "sha256:d6c56277251adf6c2bdd25249feae625abe4966831676689ff23b4694dea5b12", size = 111535, upload-time = "2025-10-28T19:26:57.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/24/3bf865b07d15fea85b63504856e137029b6acbc73762496064219cdb265d/boto3-1.40.61-py3-none-any.whl", hash = "sha256:6b9c57b2a922b5d8c17766e29ed792586a818098efe84def27c8f582b33f898c", size = 139321, upload-time = "2025-10-28T19:26:55.007Z" }, +] + +[[package]] +name = "botocore" +version = "1.40.61" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/a3/81d3a47c2dbfd76f185d3b894f2ad01a75096c006a2dd91f237dca182188/botocore-1.40.61.tar.gz", hash = "sha256:a2487ad69b090f9cccd64cf07c7021cd80ee9c0655ad974f87045b02f3ef52cd", size = 14393956, upload-time = "2025-10-28T19:26:46.108Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/c5/f6ce561004db45f0b847c2cd9b19c67c6bf348a82018a48cb718be6b58b0/botocore-1.40.61-py3-none-any.whl", hash = "sha256:17ebae412692fd4824f99cde0f08d50126dc97954008e5ba2b522eb049238aa7", size = 14055973, upload-time = "2025-10-28T19:26:42.15Z" }, +] + +[[package]] +name = "cachetools" +version = "7.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/cc/eb3fd22f3b96b8b70ce456d0854ef08434e5ca79c02bf8db3fc07ccfca87/cachetools-7.0.4.tar.gz", hash = "sha256:7042c0e4eea87812f04744ce6ee9ed3de457875eb1f82d8a206c46d6e48b6734", size = 37379, upload-time = "2026-03-08T21:37:17.133Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/bc/72adfb3f2ed19eb0317f89ea9b1eeccc670ae46bc394ec2c4ba1dd8c22b7/cachetools-7.0.4-py3-none-any.whl", hash = "sha256:0c8bb1b9ec8194fa4d764accfde602dfe52f70d0f311e62792d4c3f8c051b1e9", size = 13900, upload-time = "2026-03-08T21:37:15.805Z" }, +] + +[[package]] +name = "certifi" +version = "2026.2.25" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/9e/bcec3b22c64ecec47d39bf5167c2613efd41898c019dccd4183f6aa5d6a7/charset_normalizer-3.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:610f72c0ee565dfb8ae1241b666119582fdbfe7c0975c175be719f940e110694", size = 279531, upload-time = "2026-03-06T06:00:52.252Z" }, + { url = "https://files.pythonhosted.org/packages/58/12/81fd25f7e7078ab5d1eedbb0fac44be4904ae3370a3bf4533c8f2d159acd/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60d68e820af339df4ae8358c7a2e7596badeb61e544438e489035f9fbf3246a5", size = 188006, upload-time = "2026-03-06T06:00:53.8Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6e/f2d30e8c27c1b0736a6520311982cf5286cfc7f6cac77d7bc1325e3a23f2/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b473fc8dca1c3ad8559985794815f06ca3fc71942c969129070f2c3cdf7281", size = 205085, upload-time = "2026-03-06T06:00:55.311Z" }, + { url = "https://files.pythonhosted.org/packages/d0/90/d12cefcb53b5931e2cf792a33718d7126efb116a320eaa0742c7059a95e4/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d4eb8ac7469b2a5d64b5b8c04f84d8bf3ad340f4514b98523805cbf46e3b3923", size = 200545, upload-time = "2026-03-06T06:00:56.532Z" }, + { url = "https://files.pythonhosted.org/packages/03/f4/44d3b830a20e89ff82a3134912d9a1cf6084d64f3b95dcad40f74449a654/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bcb3227c3d9aaf73eaaab1db7ccd80a8995c509ee9941e2aae060ca6e4e5d81", size = 193863, upload-time = "2026-03-06T06:00:57.823Z" }, + { url = "https://files.pythonhosted.org/packages/25/4b/f212119c18a6320a9d4a730d1b4057875cdeabf21b3614f76549042ef8a8/charset_normalizer-3.4.5-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:75ee9c1cce2911581a70a3c0919d8bccf5b1cbc9b0e5171400ec736b4b569497", size = 181827, upload-time = "2026-03-06T06:00:59.323Z" }, + { url = "https://files.pythonhosted.org/packages/74/00/b26158e48b425a202a92965f8069e8a63d9af1481dfa206825d7f74d2a3c/charset_normalizer-3.4.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d1401945cb77787dbd3af2446ff2d75912327c4c3a1526ab7955ecf8600687c", size = 191085, upload-time = "2026-03-06T06:01:00.546Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c2/1c1737bf6fd40335fe53d28fe49afd99ee4143cc57a845e99635ce0b9b6d/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a45e504f5e1be0bd385935a8e1507c442349ca36f511a47057a71c9d1d6ea9e", size = 190688, upload-time = "2026-03-06T06:01:02.479Z" }, + { url = "https://files.pythonhosted.org/packages/5a/3d/abb5c22dc2ef493cd56522f811246a63c5427c08f3e3e50ab663de27fcf4/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e09f671a54ce70b79a1fc1dc6da3072b7ef7251fadb894ed92d9aa8218465a5f", size = 183077, upload-time = "2026-03-06T06:01:04.231Z" }, + { url = "https://files.pythonhosted.org/packages/44/33/5298ad4d419a58e25b3508e87f2758d1442ff00c2471f8e0403dab8edad5/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d01de5e768328646e6a3fa9e562706f8f6641708c115c62588aef2b941a4f88e", size = 206706, upload-time = "2026-03-06T06:01:05.773Z" }, + { url = "https://files.pythonhosted.org/packages/7b/17/51e7895ac0f87c3b91d276a449ef09f5532a7529818f59646d7a55089432/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:131716d6786ad5e3dc542f5cc6f397ba3339dc0fb87f87ac30e550e8987756af", size = 191665, upload-time = "2026-03-06T06:01:07.473Z" }, + { url = "https://files.pythonhosted.org/packages/90/8f/cce9adf1883e98906dbae380d769b4852bb0fa0004bc7d7a2243418d3ea8/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a374cc0b88aa710e8865dc1bd6edb3743c59f27830f0293ab101e4cf3ce9f85", size = 201950, upload-time = "2026-03-06T06:01:08.973Z" }, + { url = "https://files.pythonhosted.org/packages/08/ca/bce99cd5c397a52919e2769d126723f27a4c037130374c051c00470bcd38/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d31f0d1671e1534e395f9eb84a68e0fb670e1edb1fe819a9d7f564ae3bc4e53f", size = 195830, upload-time = "2026-03-06T06:01:10.155Z" }, + { url = "https://files.pythonhosted.org/packages/87/4f/2e3d023a06911f1281f97b8f036edc9872167036ca6f55cc874a0be6c12c/charset_normalizer-3.4.5-cp311-cp311-win32.whl", hash = "sha256:cace89841c0599d736d3d74a27bc5821288bb47c5441923277afc6059d7fbcb4", size = 132029, upload-time = "2026-03-06T06:01:11.706Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1f/a853b73d386521fd44b7f67ded6b17b7b2367067d9106a5c4b44f9a34274/charset_normalizer-3.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:f8102ae93c0bc863b1d41ea0f4499c20a83229f52ed870850892df555187154a", size = 142404, upload-time = "2026-03-06T06:01:12.865Z" }, + { url = "https://files.pythonhosted.org/packages/b4/10/dba36f76b71c38e9d391abe0fd8a5b818790e053c431adecfc98c35cd2a9/charset_normalizer-3.4.5-cp311-cp311-win_arm64.whl", hash = "sha256:ed98364e1c262cf5f9363c3eca8c2df37024f52a8fa1180a3610014f26eac51c", size = 132796, upload-time = "2026-03-06T06:01:14.106Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b6/9ee9c1a608916ca5feae81a344dffbaa53b26b90be58cc2159e3332d44ec/charset_normalizer-3.4.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade", size = 280976, upload-time = "2026-03-06T06:01:15.276Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d8/a54f7c0b96f1df3563e9190f04daf981e365a9b397eedfdfb5dbef7e5c6c/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54", size = 189356, upload-time = "2026-03-06T06:01:16.511Z" }, + { url = "https://files.pythonhosted.org/packages/42/69/2bf7f76ce1446759a5787cb87d38f6a61eb47dbbdf035cfebf6347292a65/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467", size = 206369, upload-time = "2026-03-06T06:01:17.853Z" }, + { url = "https://files.pythonhosted.org/packages/10/9c/949d1a46dab56b959d9a87272482195f1840b515a3380e39986989a893ae/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60", size = 203285, upload-time = "2026-03-06T06:01:19.473Z" }, + { url = "https://files.pythonhosted.org/packages/67/5c/ae30362a88b4da237d71ea214a8c7eb915db3eec941adda511729ac25fa2/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d", size = 196274, upload-time = "2026-03-06T06:01:20.728Z" }, + { url = "https://files.pythonhosted.org/packages/b2/07/c9f2cb0e46cb6d64fdcc4f95953747b843bb2181bda678dc4e699b8f0f9a/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e", size = 184715, upload-time = "2026-03-06T06:01:22.194Z" }, + { url = "https://files.pythonhosted.org/packages/36/64/6b0ca95c44fddf692cd06d642b28f63009d0ce325fad6e9b2b4d0ef86a52/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f", size = 193426, upload-time = "2026-03-06T06:01:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/50/bc/a730690d726403743795ca3f5bb2baf67838c5fea78236098f324b965e40/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc", size = 191780, upload-time = "2026-03-06T06:01:25.053Z" }, + { url = "https://files.pythonhosted.org/packages/97/4f/6c0bc9af68222b22951552d73df4532b5be6447cee32d58e7e8c74ecbb7b/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95", size = 185805, upload-time = "2026-03-06T06:01:26.294Z" }, + { url = "https://files.pythonhosted.org/packages/dd/b9/a523fb9b0ee90814b503452b2600e4cbc118cd68714d57041564886e7325/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a", size = 208342, upload-time = "2026-03-06T06:01:27.55Z" }, + { url = "https://files.pythonhosted.org/packages/4d/61/c59e761dee4464050713e50e27b58266cc8e209e518c0b378c1580c959ba/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac", size = 193661, upload-time = "2026-03-06T06:01:29.051Z" }, + { url = "https://files.pythonhosted.org/packages/1c/43/729fa30aad69783f755c5ad8649da17ee095311ca42024742701e202dc59/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1", size = 204819, upload-time = "2026-03-06T06:01:30.298Z" }, + { url = "https://files.pythonhosted.org/packages/87/33/d9b442ce5a91b96fc0840455a9e49a611bbadae6122778d0a6a79683dd31/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98", size = 198080, upload-time = "2026-03-06T06:01:31.478Z" }, + { url = "https://files.pythonhosted.org/packages/56/5a/b8b5a23134978ee9885cee2d6995f4c27cc41f9baded0a9685eabc5338f0/charset_normalizer-3.4.5-cp312-cp312-win32.whl", hash = "sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262", size = 132630, upload-time = "2026-03-06T06:01:33.056Z" }, + { url = "https://files.pythonhosted.org/packages/70/53/e44a4c07e8904500aec95865dc3f6464dc3586a039ef0df606eb3ac38e35/charset_normalizer-3.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636", size = 142856, upload-time = "2026-03-06T06:01:34.489Z" }, + { url = "https://files.pythonhosted.org/packages/ea/aa/c5628f7cad591b1cf45790b7a61483c3e36cf41349c98af7813c483fd6e8/charset_normalizer-3.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02", size = 132982, upload-time = "2026-03-06T06:01:35.641Z" }, + { url = "https://files.pythonhosted.org/packages/f5/48/9f34ec4bb24aa3fdba1890c1bddb97c8a4be1bd84ef5c42ac2352563ad05/charset_normalizer-3.4.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23", size = 280788, upload-time = "2026-03-06T06:01:37.126Z" }, + { url = "https://files.pythonhosted.org/packages/0e/09/6003e7ffeb90cc0560da893e3208396a44c210c5ee42efff539639def59b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8", size = 188890, upload-time = "2026-03-06T06:01:38.73Z" }, + { url = "https://files.pythonhosted.org/packages/42/1e/02706edf19e390680daa694d17e2b8eab4b5f7ac285e2a51168b4b22ee6b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d", size = 206136, upload-time = "2026-03-06T06:01:40.016Z" }, + { url = "https://files.pythonhosted.org/packages/c7/87/942c3def1b37baf3cf786bad01249190f3ca3d5e63a84f831e704977de1f/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce", size = 202551, upload-time = "2026-03-06T06:01:41.522Z" }, + { url = "https://files.pythonhosted.org/packages/94/0a/af49691938dfe175d71b8a929bd7e4ace2809c0c5134e28bc535660d5262/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819", size = 195572, upload-time = "2026-03-06T06:01:43.208Z" }, + { url = "https://files.pythonhosted.org/packages/20/ea/dfb1792a8050a8e694cfbde1570ff97ff74e48afd874152d38163d1df9ae/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d", size = 184438, upload-time = "2026-03-06T06:01:44.755Z" }, + { url = "https://files.pythonhosted.org/packages/72/12/c281e2067466e3ddd0595bfaea58a6946765ace5c72dfa3edc2f5f118026/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763", size = 193035, upload-time = "2026-03-06T06:01:46.051Z" }, + { url = "https://files.pythonhosted.org/packages/ba/4f/3792c056e7708e10464bad0438a44708886fb8f92e3c3d29ec5e2d964d42/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9", size = 191340, upload-time = "2026-03-06T06:01:47.547Z" }, + { url = "https://files.pythonhosted.org/packages/e7/86/80ddba897127b5c7a9bccc481b0cd36c8fefa485d113262f0fe4332f0bf4/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c", size = 185464, upload-time = "2026-03-06T06:01:48.764Z" }, + { url = "https://files.pythonhosted.org/packages/4d/00/b5eff85ba198faacab83e0e4b6f0648155f072278e3b392a82478f8b988b/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67", size = 208014, upload-time = "2026-03-06T06:01:50.371Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/d36f70be01597fd30850dde8a1269ebc8efadd23ba5785808454f2389bde/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3", size = 193297, upload-time = "2026-03-06T06:01:51.933Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1d/259eb0a53d4910536c7c2abb9cb25f4153548efb42800c6a9456764649c0/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf", size = 204321, upload-time = "2026-03-06T06:01:53.887Z" }, + { url = "https://files.pythonhosted.org/packages/84/31/faa6c5b9d3688715e1ed1bb9d124c384fe2fc1633a409e503ffe1c6398c1/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6", size = 197509, upload-time = "2026-03-06T06:01:56.439Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a5/c7d9dd1503ffc08950b3260f5d39ec2366dd08254f0900ecbcf3a6197c7c/charset_normalizer-3.4.5-cp313-cp313-win32.whl", hash = "sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f", size = 132284, upload-time = "2026-03-06T06:01:57.812Z" }, + { url = "https://files.pythonhosted.org/packages/b9/0f/57072b253af40c8aa6636e6de7d75985624c1eb392815b2f934199340a89/charset_normalizer-3.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7", size = 142630, upload-time = "2026-03-06T06:01:59.062Z" }, + { url = "https://files.pythonhosted.org/packages/31/41/1c4b7cc9f13bd9d369ce3bc993e13d374ce25fa38a2663644283ecf422c1/charset_normalizer-3.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36", size = 133254, upload-time = "2026-03-06T06:02:00.281Z" }, + { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "cloudpickle" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" }, + { url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" }, + { url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" }, + { url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" }, + { url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" }, + { url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" }, + { url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" }, + { url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" }, + { url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" }, + { url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" }, + { url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" }, + { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" }, + { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" }, + { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" }, + { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" }, + { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" }, + { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" }, + { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" }, + { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" }, + { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" }, + { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" }, + { url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" }, + { url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" }, + { url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" }, + { url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" }, + { url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" }, + { url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" }, + { url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" }, + { url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" }, + { url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" }, + { url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" }, + { url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" }, + { url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" }, + { url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" }, + { url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" }, + { url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" }, + { url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" }, + { url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" }, + { url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cryptography" +version = "46.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, + { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, + { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, + { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, + { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, + { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, + { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, + { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, + { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, + { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, + { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, + { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, + { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, + { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, + { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" }, + { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" }, + { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" }, + { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" }, +] + +[[package]] +name = "cuda-bindings" +version = "12.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-pathfinder" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/e7/b47792cc2d01c7e1d37c32402182524774dadd2d26339bd224e0e913832e/cuda_bindings-12.9.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c912a3d9e6b6651853eed8eed96d6800d69c08e94052c292fec3f282c5a817c9", size = 12210593, upload-time = "2025-10-21T14:51:36.574Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c1/dabe88f52c3e3760d861401bb994df08f672ec893b8f7592dc91626adcf3/cuda_bindings-12.9.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fda147a344e8eaeca0c6ff113d2851ffca8f7dfc0a6c932374ee5c47caa649c8", size = 12151019, upload-time = "2025-10-21T14:51:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/56/e465c31dc9111be3441a9ba7df1941fe98f4aa6e71e8788a3fb4534ce24d/cuda_bindings-12.9.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:32bdc5a76906be4c61eb98f546a6786c5773a881f3b166486449b5d141e4a39f", size = 11906628, upload-time = "2025-10-21T14:51:49.905Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/1e6be415e37478070aeeee5884c2022713c1ecc735e6d82d744de0252eee/cuda_bindings-12.9.4-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56e0043c457a99ac473ddc926fe0dc4046694d99caef633e92601ab52cbe17eb", size = 11925991, upload-time = "2025-10-21T14:51:56.535Z" }, +] + +[[package]] +name = "cuda-pathfinder" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/02/59a5bc738a09def0b49aea0e460bdf97f65206d0d041246147cf6207e69c/cuda_pathfinder-1.4.1-py3-none-any.whl", hash = "sha256:40793006082de88e0950753655e55558a446bed9a7d9d0bcb48b2506d50ed82a", size = 43903, upload-time = "2026-03-06T21:05:24.372Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "dask" +version = "2026.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "cloudpickle" }, + { name = "fsspec" }, + { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, + { name = "packaging" }, + { name = "partd" }, + { name = "pyyaml" }, + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/52/b0f9172b22778def907db1ff173249e4eb41f054b46a9c83b1528aaf811f/dask-2026.1.2.tar.gz", hash = "sha256:1136683de2750d98ea792670f7434e6c1cfce90cab2cc2f2495a9e60fd25a4fc", size = 10997838, upload-time = "2026-01-30T21:04:20.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/23/d39ccc4ed76222db31530b0a7d38876fdb7673e23f838e8d8f0ed4651a4f/dask-2026.1.2-py3-none-any.whl", hash = "sha256:46a0cf3b8d87f78a3d2e6b145aea4418a6d6d606fe6a16c79bd8ca2bb862bc91", size = 1482084, upload-time = "2026-01-30T21:04:18.363Z" }, +] + +[[package]] +name = "dataclasses-json" +version = "0.6.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, +] + +[[package]] +name = "datasets" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, + { name = "filelock" }, + { name = "fsspec", extra = ["http"] }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "multiprocess" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pyarrow" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/94/eb81c6fe32e9b6ef92223141b5a553aeff2e9456968424a8533cbe88f476/datasets-4.6.1.tar.gz", hash = "sha256:140ce500bc41939ff6ce995702d66b1f4b2ee7f117bb9b07512fab6804d4070a", size = 593865, upload-time = "2026-02-27T23:26:49.482Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/f0/99fe6eb530c7ee9ee1faee48059eb8a6437f80c893a496b98a78864e0fc6/datasets-4.6.1-py3-none-any.whl", hash = "sha256:f53228e6dadc9f837037b1bf3051d7d8c054abbb3eb29f1f022926e08090e0da", size = 520667, upload-time = "2026-02-27T23:26:46.855Z" }, +] + +[[package]] +name = "dill" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, +] + +[[package]] +name = "distributed" +version = "2026.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "cloudpickle" }, + { name = "dask" }, + { name = "jinja2" }, + { name = "locket" }, + { name = "msgpack" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyyaml" }, + { name = "sortedcontainers" }, + { name = "tblib" }, + { name = "toolz" }, + { name = "tornado" }, + { name = "urllib3" }, + { name = "zict" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/75/b6e5b77229097ff03dd5ba6a07c77e2da87e7e991ccfef412549bba78746/distributed-2026.1.2.tar.gz", hash = "sha256:8333fa7a34151ed3b4cf1a03136fe1f1799eca706a5e47bdb63022c8795d853b", size = 2103721, upload-time = "2026-01-30T21:07:03.307Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/14/0fe5889a83991ac29c93e6b2e121ad2afc3bff5f9327f34447d3068d8142/distributed-2026.1.2-py3-none-any.whl", hash = "sha256:30ccb5587351f50304f6f6e219ea91bc09d88401125779caa8be5253e9d3ecf2", size = 1009083, upload-time = "2026-01-30T21:07:01.363Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "et-xmlfile" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, +] + +[[package]] +name = "expandvars" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/64/a9d8ea289d663a44b346203a24bf798507463db1e76679eaa72ee6de1c7a/expandvars-1.1.2.tar.gz", hash = "sha256:6c5822b7b756a99a356b915dd1267f52ab8a4efaa135963bd7f4bd5d368f71d7", size = 70842, upload-time = "2025-09-12T10:55:20.929Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/e6/79c43f7a55264e479a9fbf21ddba6a73530b3ea8439a8bb7fa5a281721af/expandvars-1.1.2-py3-none-any.whl", hash = "sha256:d1652fe4e61914f5b88ada93aaedb396446f55ae4621de45c8cb9f66e5712526", size = 7526, upload-time = "2025-09-12T10:55:18.779Z" }, +] + +[[package]] +name = "fastapi" +version = "0.135.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, +] + +[[package]] +name = "fastuuid" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/f3/12481bda4e5b6d3e698fbf525df4443cc7dce746f246b86b6fcb2fba1844/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73946cb950c8caf65127d4e9a325e2b6be0442a224fd51ba3b6ac44e1912ce34", size = 516386, upload-time = "2025-10-19T22:42:40.176Z" }, + { url = "https://files.pythonhosted.org/packages/59/19/2fc58a1446e4d72b655648eb0879b04e88ed6fa70d474efcf550f640f6ec/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:12ac85024637586a5b69645e7ed986f7535106ed3013640a393a03e461740cb7", size = 264569, upload-time = "2025-10-19T22:25:50.977Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/3c74756e5b02c40cfcc8b1d8b5bac4edbd532b55917a6bcc9113550e99d1/fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05a8dde1f395e0c9b4be515b7a521403d1e8349443e7641761af07c7ad1624b1", size = 254366, upload-time = "2025-10-19T22:29:49.166Z" }, + { url = "https://files.pythonhosted.org/packages/52/96/d761da3fccfa84f0f353ce6e3eb8b7f76b3aa21fd25e1b00a19f9c80a063/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09378a05020e3e4883dfdab438926f31fea15fd17604908f3d39cbeb22a0b4dc", size = 278978, upload-time = "2025-10-19T22:35:41.306Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c2/f84c90167cc7765cb82b3ff7808057608b21c14a38531845d933a4637307/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbb0c4b15d66b435d2538f3827f05e44e2baafcc003dd7d8472dc67807ab8fd8", size = 279692, upload-time = "2025-10-19T22:25:36.997Z" }, + { url = "https://files.pythonhosted.org/packages/af/7b/4bacd03897b88c12348e7bd77943bac32ccf80ff98100598fcff74f75f2e/fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd5a7f648d4365b41dbf0e38fe8da4884e57bed4e77c83598e076ac0c93995e7", size = 303384, upload-time = "2025-10-19T22:29:46.578Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a2/584f2c29641df8bd810d00c1f21d408c12e9ad0c0dafdb8b7b29e5ddf787/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c0a94245afae4d7af8c43b3159d5e3934c53f47140be0be624b96acd672ceb73", size = 460921, upload-time = "2025-10-19T22:36:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/c6b77443bb7764c760e211002c8638c0c7cce11cb584927e723215ba1398/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b29e23c97e77c3a9514d70ce343571e469098ac7f5a269320a0f0b3e193ab36", size = 480575, upload-time = "2025-10-19T22:28:18.975Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/93f553111b33f9bb83145be12868c3c475bf8ea87c107063d01377cc0e8e/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e690d48f923c253f28151b3a6b4e335f2b06bf669c68a02665bc150b7839e94", size = 452317, upload-time = "2025-10-19T22:25:32.75Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8c/a04d486ca55b5abb7eaa65b39df8d891b7b1635b22db2163734dc273579a/fastuuid-0.14.0-cp311-cp311-win32.whl", hash = "sha256:a6f46790d59ab38c6aa0e35c681c0484b50dc0acf9e2679c005d61e019313c24", size = 154804, upload-time = "2025-10-19T22:24:15.615Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b2/2d40bf00820de94b9280366a122cbaa60090c8cf59e89ac3938cf5d75895/fastuuid-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:e150eab56c95dc9e3fefc234a0eedb342fac433dacc273cd4d150a5b0871e1fa", size = 156099, upload-time = "2025-10-19T22:24:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/e78fcc5df65467f0d207661b7ef86c5b7ac62eea337c0c0fcedbeee6fb13/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77e94728324b63660ebf8adb27055e92d2e4611645bf12ed9d88d30486471d0a", size = 510164, upload-time = "2025-10-19T22:31:45.635Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b3/c846f933f22f581f558ee63f81f29fa924acd971ce903dab1a9b6701816e/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:caa1f14d2102cb8d353096bc6ef6c13b2c81f347e6ab9d6fbd48b9dea41c153d", size = 261837, upload-time = "2025-10-19T22:38:38.53Z" }, + { url = "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d23ef06f9e67163be38cece704170486715b177f6baae338110983f99a72c070", size = 251370, upload-time = "2025-10-19T22:40:26.07Z" }, + { url = "https://files.pythonhosted.org/packages/14/dd/5927f0a523d8e6a76b70968e6004966ee7df30322f5fc9b6cdfb0276646a/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9ec605ace243b6dbe3bd27ebdd5d33b00d8d1d3f580b39fdd15cd96fd71796", size = 277766, upload-time = "2025-10-19T22:37:23.779Z" }, + { url = "https://files.pythonhosted.org/packages/16/6e/c0fb547eef61293153348f12e0f75a06abb322664b34a1573a7760501336/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:808527f2407f58a76c916d6aa15d58692a4a019fdf8d4c32ac7ff303b7d7af09", size = 278105, upload-time = "2025-10-19T22:26:56.821Z" }, + { url = "https://files.pythonhosted.org/packages/2d/b1/b9c75e03b768f61cf2e84ee193dc18601aeaf89a4684b20f2f0e9f52b62c/fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb3c0d7fef6674bbeacdd6dbd386924a7b60b26de849266d1ff6602937675c8", size = 301564, upload-time = "2025-10-19T22:30:31.604Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fa/f7395fdac07c7a54f18f801744573707321ca0cee082e638e36452355a9d/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab3f5d36e4393e628a4df337c2c039069344db5f4b9d2a3c9cea48284f1dd741", size = 459659, upload-time = "2025-10-19T22:31:32.341Z" }, + { url = "https://files.pythonhosted.org/packages/66/49/c9fd06a4a0b1f0f048aacb6599e7d96e5d6bc6fa680ed0d46bf111929d1b/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b9a0ca4f03b7e0b01425281ffd44e99d360e15c895f1907ca105854ed85e2057", size = 478430, upload-time = "2025-10-19T22:26:22.962Z" }, + { url = "https://files.pythonhosted.org/packages/be/9c/909e8c95b494e8e140e8be6165d5fc3f61fdc46198c1554df7b3e1764471/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3acdf655684cc09e60fb7e4cf524e8f42ea760031945aa8086c7eae2eeeabeb8", size = 450894, upload-time = "2025-10-19T22:27:01.647Z" }, + { url = "https://files.pythonhosted.org/packages/90/eb/d29d17521976e673c55ef7f210d4cdd72091a9ec6755d0fd4710d9b3c871/fastuuid-0.14.0-cp312-cp312-win32.whl", hash = "sha256:9579618be6280700ae36ac42c3efd157049fe4dd40ca49b021280481c78c3176", size = 154374, upload-time = "2025-10-19T22:29:19.879Z" }, + { url = "https://files.pythonhosted.org/packages/cc/fc/f5c799a6ea6d877faec0472d0b27c079b47c86b1cdc577720a5386483b36/fastuuid-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:d9e4332dc4ba054434a9594cbfaf7823b57993d7d8e7267831c3e059857cf397", size = 156550, upload-time = "2025-10-19T22:27:49.658Z" }, + { url = "https://files.pythonhosted.org/packages/a5/83/ae12dd39b9a39b55d7f90abb8971f1a5f3c321fd72d5aa83f90dc67fe9ed/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021", size = 510720, upload-time = "2025-10-19T22:42:34.633Z" }, + { url = "https://files.pythonhosted.org/packages/53/b0/a4b03ff5d00f563cc7546b933c28cb3f2a07344b2aec5834e874f7d44143/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc", size = 262024, upload-time = "2025-10-19T22:30:25.482Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5", size = 251679, upload-time = "2025-10-19T22:36:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/a7e9cda8369e4f7919d36552db9b2ae21db7915083bc6336f1b0082c8b2e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f", size = 277862, upload-time = "2025-10-19T22:36:23.302Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d3/8ce11827c783affffd5bd4d6378b28eb6cc6d2ddf41474006b8d62e7448e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87", size = 278278, upload-time = "2025-10-19T22:29:43.809Z" }, + { url = "https://files.pythonhosted.org/packages/a2/51/680fb6352d0bbade04036da46264a8001f74b7484e2fd1f4da9e3db1c666/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b", size = 301788, upload-time = "2025-10-19T22:36:06.825Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7c/2014b5785bd8ebdab04ec857635ebd84d5ee4950186a577db9eff0fb8ff6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022", size = 459819, upload-time = "2025-10-19T22:35:31.623Z" }, + { url = "https://files.pythonhosted.org/packages/01/d2/524d4ceeba9160e7a9bc2ea3e8f4ccf1ad78f3bde34090ca0c51f09a5e91/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995", size = 478546, upload-time = "2025-10-19T22:26:03.023Z" }, + { url = "https://files.pythonhosted.org/packages/bc/17/354d04951ce114bf4afc78e27a18cfbd6ee319ab1829c2d5fb5e94063ac6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab", size = 450921, upload-time = "2025-10-19T22:31:02.151Z" }, + { url = "https://files.pythonhosted.org/packages/fb/be/d7be8670151d16d88f15bb121c5b66cdb5ea6a0c2a362d0dcf30276ade53/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad", size = 154559, upload-time = "2025-10-19T22:36:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/22/1d/5573ef3624ceb7abf4a46073d3554e37191c868abc3aecd5289a72f9810a/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed", size = 156539, upload-time = "2025-10-19T22:33:35.898Z" }, +] + +[[package]] +name = "filelock" +version = "3.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/77/18/a1fd2231c679dcb9726204645721b12498aeac28e1ad0601038f94b42556/filelock-3.25.0.tar.gz", hash = "sha256:8f00faf3abf9dc730a1ffe9c354ae5c04e079ab7d3a683b7c32da5dd05f26af3", size = 40158, upload-time = "2026-03-01T15:08:45.916Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl", hash = "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", size = 26427, upload-time = "2026-03-01T15:08:44.593Z" }, +] + +[[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 = "flask" +version = "3.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blinker" }, + { name = "click" }, + { name = "itsdangerous" }, + { name = "jinja2" }, + { name = "markupsafe" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/00/35d85dcce6c57fdc871f3867d465d780f302a175ea360f62533f12b27e2b/flask-3.1.3.tar.gz", hash = "sha256:0ef0e52b8a9cd932855379197dd8f94047b359ca0a78695144304cb45f87c9eb", size = 759004, upload-time = "2026-02-19T05:00:57.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl", hash = "sha256:f4bcbefc124291925f1a26446da31a5178f9483862233b23c0c96a20701f670c", size = 103424, upload-time = "2026-02-19T05:00:56.027Z" }, +] + +[[package]] +name = "fonttools" +version = "4.61.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/12/bf9f4eaa2fad039356cc627587e30ed008c03f1cebd3034376b5ee8d1d44/fonttools-4.61.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09", size = 2852213, upload-time = "2025-12-12T17:29:46.675Z" }, + { url = "https://files.pythonhosted.org/packages/ac/49/4138d1acb6261499bedde1c07f8c2605d1d8f9d77a151e5507fd3ef084b6/fonttools-4.61.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37", size = 2401689, upload-time = "2025-12-12T17:29:48.769Z" }, + { url = "https://files.pythonhosted.org/packages/e5/fe/e6ce0fe20a40e03aef906af60aa87668696f9e4802fa283627d0b5ed777f/fonttools-4.61.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb", size = 5058809, upload-time = "2025-12-12T17:29:51.701Z" }, + { url = "https://files.pythonhosted.org/packages/79/61/1ca198af22f7dd22c17ab86e9024ed3c06299cfdb08170640e9996d501a0/fonttools-4.61.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9", size = 5036039, upload-time = "2025-12-12T17:29:53.659Z" }, + { url = "https://files.pythonhosted.org/packages/99/cc/fa1801e408586b5fce4da9f5455af8d770f4fc57391cd5da7256bb364d38/fonttools-4.61.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87", size = 5034714, upload-time = "2025-12-12T17:29:55.592Z" }, + { url = "https://files.pythonhosted.org/packages/bf/aa/b7aeafe65adb1b0a925f8f25725e09f078c635bc22754f3fecb7456955b0/fonttools-4.61.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56", size = 5158648, upload-time = "2025-12-12T17:29:57.861Z" }, + { url = "https://files.pythonhosted.org/packages/99/f9/08ea7a38663328881384c6e7777bbefc46fd7d282adfd87a7d2b84ec9d50/fonttools-4.61.1-cp311-cp311-win32.whl", hash = "sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a", size = 2280681, upload-time = "2025-12-12T17:29:59.943Z" }, + { url = "https://files.pythonhosted.org/packages/07/ad/37dd1ae5fa6e01612a1fbb954f0927681f282925a86e86198ccd7b15d515/fonttools-4.61.1-cp311-cp311-win_amd64.whl", hash = "sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7", size = 2331951, upload-time = "2025-12-12T17:30:02.254Z" }, + { url = "https://files.pythonhosted.org/packages/6f/16/7decaa24a1bd3a70c607b2e29f0adc6159f36a7e40eaba59846414765fd4/fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e", size = 2851593, upload-time = "2025-12-12T17:30:04.225Z" }, + { url = "https://files.pythonhosted.org/packages/94/98/3c4cb97c64713a8cf499b3245c3bf9a2b8fd16a3e375feff2aed78f96259/fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2", size = 2400231, upload-time = "2025-12-12T17:30:06.47Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/82dbef0f6342eb01f54bca073ac1498433d6ce71e50c3c3282b655733b31/fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796", size = 4954103, upload-time = "2025-12-12T17:30:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/6c/44/f3aeac0fa98e7ad527f479e161aca6c3a1e47bb6996b053d45226fe37bf2/fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d", size = 5004295, upload-time = "2025-12-12T17:30:10.56Z" }, + { url = "https://files.pythonhosted.org/packages/14/e8/7424ced75473983b964d09f6747fa09f054a6d656f60e9ac9324cf40c743/fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8", size = 4944109, upload-time = "2025-12-12T17:30:12.874Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8b/6391b257fa3d0b553d73e778f953a2f0154292a7a7a085e2374b111e5410/fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0", size = 5093598, upload-time = "2025-12-12T17:30:15.79Z" }, + { url = "https://files.pythonhosted.org/packages/d9/71/fd2ea96cdc512d92da5678a1c98c267ddd4d8c5130b76d0f7a80f9a9fde8/fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261", size = 2269060, upload-time = "2025-12-12T17:30:18.058Z" }, + { url = "https://files.pythonhosted.org/packages/80/3b/a3e81b71aed5a688e89dfe0e2694b26b78c7d7f39a5ffd8a7d75f54a12a8/fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9", size = 2319078, upload-time = "2025-12-12T17:30:22.862Z" }, + { url = "https://files.pythonhosted.org/packages/4b/cf/00ba28b0990982530addb8dc3e9e6f2fa9cb5c20df2abdda7baa755e8fe1/fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c", size = 2846454, upload-time = "2025-12-12T17:30:24.938Z" }, + { url = "https://files.pythonhosted.org/packages/5a/ca/468c9a8446a2103ae645d14fee3f610567b7042aba85031c1c65e3ef7471/fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e", size = 2398191, upload-time = "2025-12-12T17:30:27.343Z" }, + { url = "https://files.pythonhosted.org/packages/a3/4b/d67eedaed19def5967fade3297fed8161b25ba94699efc124b14fb68cdbc/fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5", size = 4928410, upload-time = "2025-12-12T17:30:29.771Z" }, + { url = "https://files.pythonhosted.org/packages/b0/8d/6fb3494dfe61a46258cd93d979cf4725ded4eb46c2a4ca35e4490d84daea/fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd", size = 4984460, upload-time = "2025-12-12T17:30:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/f7/f1/a47f1d30b3dc00d75e7af762652d4cbc3dff5c2697a0dbd5203c81afd9c3/fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3", size = 4925800, upload-time = "2025-12-12T17:30:34.339Z" }, + { url = "https://files.pythonhosted.org/packages/a7/01/e6ae64a0981076e8a66906fab01539799546181e32a37a0257b77e4aa88b/fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d", size = 5067859, upload-time = "2025-12-12T17:30:36.593Z" }, + { url = "https://files.pythonhosted.org/packages/73/aa/28e40b8d6809a9b5075350a86779163f074d2b617c15d22343fce81918db/fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c", size = 2267821, upload-time = "2025-12-12T17:30:38.478Z" }, + { url = "https://files.pythonhosted.org/packages/1a/59/453c06d1d83dc0951b69ef692d6b9f1846680342927df54e9a1ca91c6f90/fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b", size = 2318169, upload-time = "2025-12-12T17:30:40.951Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, +] + +[[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/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/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.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" }, +] + +[package.optional-dependencies] +http = [ + { name = "aiohttp" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.73.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/96/a0205167fa0154f4a542fd6925bdc63d039d88dab3588b875078107e6f06/googleapis_common_protos-1.73.0.tar.gz", hash = "sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a", size = 147323, upload-time = "2026-03-06T21:53:09.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/28/23eea8acd65972bbfe295ce3666b28ac510dfcb115fac089d3edb0feb00a/googleapis_common_protos-1.73.0-py3-none-any.whl", hash = "sha256:dfdaaa2e860f242046be561e6d6cb5c5f1541ae02cfbcb034371aadb2942b4e8", size = 297578, upload-time = "2026-03-06T21:52:33.933Z" }, +] + +[[package]] +name = "greenlet" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/47/16400cb42d18d7a6bb46f0626852c1718612e35dcb0dffa16bbaffdf5dd2/greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86", size = 278890, upload-time = "2026-02-20T20:19:39.263Z" }, + { url = "https://files.pythonhosted.org/packages/a3/90/42762b77a5b6aa96cd8c0e80612663d39211e8ae8a6cd47c7f1249a66262/greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f", size = 581120, upload-time = "2026-02-20T20:47:30.161Z" }, + { url = "https://files.pythonhosted.org/packages/bf/6f/f3d64f4fa0a9c7b5c5b3c810ff1df614540d5aa7d519261b53fba55d4df9/greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55", size = 594363, upload-time = "2026-02-20T20:55:56.965Z" }, + { url = "https://files.pythonhosted.org/packages/9c/8b/1430a04657735a3f23116c2e0d5eb10220928846e4537a938a41b350bed6/greenlet-3.3.2-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2", size = 605046, upload-time = "2026-02-20T21:02:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/72/83/3e06a52aca8128bdd4dcd67e932b809e76a96ab8c232a8b025b2850264c5/greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358", size = 594156, upload-time = "2026-02-20T20:20:59.955Z" }, + { url = "https://files.pythonhosted.org/packages/70/79/0de5e62b873e08fe3cef7dbe84e5c4bc0e8ed0c7ff131bccb8405cd107c8/greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99", size = 1554649, upload-time = "2026-02-20T20:49:32.293Z" }, + { url = "https://files.pythonhosted.org/packages/5a/00/32d30dee8389dc36d42170a9c66217757289e2afb0de59a3565260f38373/greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be", size = 1619472, upload-time = "2026-02-20T20:21:07.966Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3a/efb2cf697fbccdf75b24e2c18025e7dfa54c4f31fab75c51d0fe79942cef/greenlet-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5", size = 230389, upload-time = "2026-02-20T20:17:18.772Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a1/65bbc059a43a7e2143ec4fc1f9e3f673e04f9c7b371a494a101422ac4fd5/greenlet-3.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd", size = 229645, upload-time = "2026-02-20T20:18:18.695Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" }, + { url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" }, + { url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c5/cc09412a29e43406eba18d61c70baa936e299bc27e074e2be3806ed29098/greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb", size = 626250, upload-time = "2026-02-20T21:02:46.596Z" }, + { url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" }, + { url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" }, + { url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/cc802e067d02af8b60b6771cea7d57e21ef5e6659912814babb42b864713/greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f", size = 231081, upload-time = "2026-02-20T20:17:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/58/2e/fe7f36ff1982d6b10a60d5e0740c759259a7d6d2e1dc41da6d96de32fff6/greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643", size = 230331, upload-time = "2026-02-20T20:17:23.34Z" }, + { url = "https://files.pythonhosted.org/packages/ac/48/f8b875fa7dea7dd9b33245e37f065af59df6a25af2f9561efa8d822fde51/greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4", size = 279120, upload-time = "2026-02-20T20:19:01.9Z" }, + { url = "https://files.pythonhosted.org/packages/49/8d/9771d03e7a8b1ee456511961e1b97a6d77ae1dea4a34a5b98eee706689d3/greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986", size = 603238, upload-time = "2026-02-20T20:47:32.873Z" }, + { url = "https://files.pythonhosted.org/packages/59/0e/4223c2bbb63cd5c97f28ffb2a8aee71bdfb30b323c35d409450f51b91e3e/greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92", size = 614219, upload-time = "2026-02-20T20:55:59.817Z" }, + { url = "https://files.pythonhosted.org/packages/94/2b/4d012a69759ac9d77210b8bfb128bc621125f5b20fc398bce3940d036b1c/greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd", size = 628268, upload-time = "2026-02-20T21:02:48.024Z" }, + { url = "https://files.pythonhosted.org/packages/7a/34/259b28ea7a2a0c904b11cd36c79b8cef8019b26ee5dbe24e73b469dea347/greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab", size = 616774, upload-time = "2026-02-20T20:21:02.454Z" }, + { url = "https://files.pythonhosted.org/packages/0a/03/996c2d1689d486a6e199cb0f1cf9e4aa940c500e01bdf201299d7d61fa69/greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a", size = 1571277, upload-time = "2026-02-20T20:49:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c4/2570fc07f34a39f2caf0bf9f24b0a1a0a47bc2e8e465b2c2424821389dfc/greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b", size = 1640455, upload-time = "2026-02-20T20:21:10.261Z" }, + { url = "https://files.pythonhosted.org/packages/91/39/5ef5aa23bc545aa0d31e1b9b55822b32c8da93ba657295840b6b34124009/greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124", size = 230961, upload-time = "2026-02-20T20:16:58.461Z" }, + { url = "https://files.pythonhosted.org/packages/62/6b/a89f8456dcb06becff288f563618e9f20deed8dd29beea14f9a168aef64b/greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327", size = 230221, upload-time = "2026-02-20T20:17:37.152Z" }, +] + +[[package]] +name = "grpcio" +version = "1.78.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/c7/d0b780a29b0837bf4ca9580904dfb275c1fc321ded7897d620af7047ec57/grpcio-1.78.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2777b783f6c13b92bd7b716667452c329eefd646bfb3f2e9dabea2e05dbd34f6", size = 5951525, upload-time = "2026-02-06T09:55:01.989Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b1/96920bf2ee61df85a9503cb6f733fe711c0ff321a5a697d791b075673281/grpcio-1.78.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:9dca934f24c732750389ce49d638069c3892ad065df86cb465b3fa3012b70c9e", size = 11830418, upload-time = "2026-02-06T09:55:04.462Z" }, + { url = "https://files.pythonhosted.org/packages/83/0c/7c1528f098aeb75a97de2bae18c530f56959fb7ad6c882db45d9884d6edc/grpcio-1.78.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:459ab414b35f4496138d0ecd735fed26f1318af5e52cb1efbc82a09f0d5aa911", size = 6524477, upload-time = "2026-02-06T09:55:07.111Z" }, + { url = "https://files.pythonhosted.org/packages/8d/52/e7c1f3688f949058e19a011c4e0dec973da3d0ae5e033909677f967ae1f4/grpcio-1.78.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:082653eecbdf290e6e3e2c276ab2c54b9e7c299e07f4221872380312d8cf395e", size = 7198266, upload-time = "2026-02-06T09:55:10.016Z" }, + { url = "https://files.pythonhosted.org/packages/e5/61/8ac32517c1e856677282c34f2e7812d6c328fa02b8f4067ab80e77fdc9c9/grpcio-1.78.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85f93781028ec63f383f6bc90db785a016319c561cc11151fbb7b34e0d012303", size = 6730552, upload-time = "2026-02-06T09:55:12.207Z" }, + { url = "https://files.pythonhosted.org/packages/bd/98/b8ee0158199250220734f620b12e4a345955ac7329cfd908d0bf0fda77f0/grpcio-1.78.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f12857d24d98441af6a1d5c87442d624411db486f7ba12550b07788f74b67b04", size = 7304296, upload-time = "2026-02-06T09:55:15.044Z" }, + { url = "https://files.pythonhosted.org/packages/bd/0f/7b72762e0d8840b58032a56fdbd02b78fc645b9fa993d71abf04edbc54f4/grpcio-1.78.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5397fff416b79e4b284959642a4e95ac4b0f1ece82c9993658e0e477d40551ec", size = 8288298, upload-time = "2026-02-06T09:55:17.276Z" }, + { url = "https://files.pythonhosted.org/packages/24/ae/ae4ce56bc5bb5caa3a486d60f5f6083ac3469228faa734362487176c15c5/grpcio-1.78.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbe6e89c7ffb48518384068321621b2a69cab509f58e40e4399fdd378fa6d074", size = 7730953, upload-time = "2026-02-06T09:55:19.545Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6e/8052e3a28eb6a820c372b2eb4b5e32d195c661e137d3eca94d534a4cfd8a/grpcio-1.78.0-cp311-cp311-win32.whl", hash = "sha256:6092beabe1966a3229f599d7088b38dfc8ffa1608b5b5cdda31e591e6500f856", size = 4076503, upload-time = "2026-02-06T09:55:21.521Z" }, + { url = "https://files.pythonhosted.org/packages/08/62/f22c98c5265dfad327251fa2f840b591b1df5f5e15d88b19c18c86965b27/grpcio-1.78.0-cp311-cp311-win_amd64.whl", hash = "sha256:1afa62af6e23f88629f2b29ec9e52ec7c65a7176c1e0a83292b93c76ca882558", size = 4799767, upload-time = "2026-02-06T09:55:24.107Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f4/7384ed0178203d6074446b3c4f46c90a22ddf7ae0b3aee521627f54cfc2a/grpcio-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f9ab915a267fc47c7e88c387a3a28325b58c898e23d4995f765728f4e3dedb97", size = 5913985, upload-time = "2026-02-06T09:55:26.832Z" }, + { url = "https://files.pythonhosted.org/packages/81/ed/be1caa25f06594463f685b3790b320f18aea49b33166f4141bfdc2bfb236/grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3f8904a8165ab21e07e58bf3e30a73f4dffc7a1e0dbc32d51c61b5360d26f43e", size = 11811853, upload-time = "2026-02-06T09:55:29.224Z" }, + { url = "https://files.pythonhosted.org/packages/24/a7/f06d151afc4e64b7e3cc3e872d331d011c279aaab02831e40a81c691fb65/grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:859b13906ce098c0b493af92142ad051bf64c7870fa58a123911c88606714996", size = 6475766, upload-time = "2026-02-06T09:55:31.825Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a8/4482922da832ec0082d0f2cc3a10976d84a7424707f25780b82814aafc0a/grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b2342d87af32790f934a79c3112641e7b27d63c261b8b4395350dad43eff1dc7", size = 7170027, upload-time = "2026-02-06T09:55:34.7Z" }, + { url = "https://files.pythonhosted.org/packages/54/bf/f4a3b9693e35d25b24b0b39fa46d7d8a3c439e0a3036c3451764678fec20/grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12a771591ae40bc65ba67048fa52ef4f0e6db8279e595fd349f9dfddeef571f9", size = 6690766, upload-time = "2026-02-06T09:55:36.902Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b9/521875265cc99fe5ad4c5a17010018085cae2810a928bf15ebe7d8bcd9cc/grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:185dea0d5260cbb2d224c507bf2a5444d5abbb1fa3594c1ed7e4c709d5eb8383", size = 7266161, upload-time = "2026-02-06T09:55:39.824Z" }, + { url = "https://files.pythonhosted.org/packages/05/86/296a82844fd40a4ad4a95f100b55044b4f817dece732bf686aea1a284147/grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51b13f9aed9d59ee389ad666b8c2214cc87b5de258fa712f9ab05f922e3896c6", size = 8253303, upload-time = "2026-02-06T09:55:42.353Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e4/ea3c0caf5468537f27ad5aab92b681ed7cc0ef5f8c9196d3fd42c8c2286b/grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd5f135b1bd58ab088930b3c613455796dfa0393626a6972663ccdda5b4ac6ce", size = 7698222, upload-time = "2026-02-06T09:55:44.629Z" }, + { url = "https://files.pythonhosted.org/packages/d7/47/7f05f81e4bb6b831e93271fb12fd52ba7b319b5402cbc101d588f435df00/grpcio-1.78.0-cp312-cp312-win32.whl", hash = "sha256:94309f498bcc07e5a7d16089ab984d42ad96af1d94b5a4eb966a266d9fcabf68", size = 4066123, upload-time = "2026-02-06T09:55:47.644Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e7/d6914822c88aa2974dbbd10903d801a28a19ce9cd8bad7e694cbbcf61528/grpcio-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:9566fe4ababbb2610c39190791e5b829869351d14369603702e890ef3ad2d06e", size = 4797657, upload-time = "2026-02-06T09:55:49.86Z" }, + { url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" }, + { url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" }, + { url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" }, + { url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" }, + { url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/cb/9bb543bd987ffa1ee48202cc96a756951b734b79a542335c566148ade36c/hf_xet-1.3.2.tar.gz", hash = "sha256:e130ee08984783d12717444e538587fa2119385e5bd8fc2bb9f930419b73a7af", size = 643646, upload-time = "2026-02-27T17:26:08.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/75/462285971954269432aad2e7938c5c7ff9ec7d60129cec542ab37121e3d6/hf_xet-1.3.2-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:335a8f36c55fd35a92d0062f4e9201b4015057e62747b7e7001ffb203c0ee1d2", size = 3761019, upload-time = "2026-02-27T17:25:49.441Z" }, + { url = "https://files.pythonhosted.org/packages/35/56/987b0537ddaf88e17192ea09afa8eca853e55f39a4721578be436f8409df/hf_xet-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8", size = 3521565, upload-time = "2026-02-27T17:25:47.469Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5c/7e4a33a3d689f77761156cc34558047569e54af92e4d15a8f493229f6767/hf_xet-1.3.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d", size = 4176494, upload-time = "2026-02-27T17:25:40.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b3/71e856bf9d9a69b3931837e8bf22e095775f268c8edcd4a9e8c355f92484/hf_xet-1.3.2-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c1980abfb68ecf6c1c7983379ed7b1e2b49a1aaf1a5aca9acc7d48e5e2e0a961", size = 3955601, upload-time = "2026-02-27T17:25:38.376Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/aecf97b3f0a981600a67ff4db15e2d433389d698a284bb0ea5d8fcdd6f7f/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1c88fbd90ad0d27c46b77a445f0a436ebaa94e14965c581123b68b1c52f5fd30", size = 4154770, upload-time = "2026-02-27T17:25:56.756Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e1/3af961f71a40e09bf5ee909842127b6b00f5ab4ee3817599dc0771b79893/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508", size = 4394161, upload-time = "2026-02-27T17:25:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c3/859509bade9178e21b8b1db867b8e10e9f817ab9ac1de77cb9f461ced765/hf_xet-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:31612ba0629046e425ba50375685a2586e11fb9144270ebabd75878c3eaf6378", size = 3637377, upload-time = "2026-02-27T17:26:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/05/7f/724cfbef4da92d577b71f68bf832961c8919f36c60d28d289a9fc9d024d4/hf_xet-1.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:433c77c9f4e132b562f37d66c9b22c05b5479f243a1f06a120c1c06ce8b1502a", size = 3497875, upload-time = "2026-02-27T17:26:09.034Z" }, + { url = "https://files.pythonhosted.org/packages/d8/28/dbb024e2e3907f6f3052847ca7d1a2f7a3972fafcd53ff79018977fcb3e4/hf_xet-1.3.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f93b7595f1d8fefddfede775c18b5c9256757824f7f6832930b49858483cd56f", size = 3763961, upload-time = "2026-02-27T17:25:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259", size = 3526171, upload-time = "2026-02-27T17:25:50.968Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633", size = 4180750, upload-time = "2026-02-27T17:25:43.125Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ad/bc7f41f87173d51d0bce497b171c4ee0cbde1eed2d7b4216db5d0ada9f50/hf_xet-1.3.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:06b724a361f670ae557836e57801b82c75b534812e351a87a2c739f77d1e0635", size = 3961035, upload-time = "2026-02-27T17:25:41.837Z" }, + { url = "https://files.pythonhosted.org/packages/73/38/600f4dda40c4a33133404d9fe644f1d35ff2d9babb4d0435c646c63dd107/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:305f5489d7241a47e0458ef49334be02411d1d0f480846363c1c8084ed9916f7", size = 4161378, upload-time = "2026-02-27T17:26:00.365Z" }, + { url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e", size = 4398020, upload-time = "2026-02-27T17:26:03.977Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/99bfd948a3ed3620ab709276df3ad3710dcea61976918cce8706502927af/hf_xet-1.3.2-cp37-abi3-win_amd64.whl", hash = "sha256:9298b47cce6037b7045ae41482e703c471ce36b52e73e49f71226d2e8e5685a1", size = 3641624, upload-time = "2026-02-27T17:26:13.542Z" }, + { url = "https://files.pythonhosted.org/packages/cc/02/9a6e4ca1f3f73a164c0cd48e41b3cc56585dcc37e809250de443d673266f/hf_xet-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", size = 3503976, upload-time = "2026-02-27T17:26:12.123Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httptools" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/08/17e07e8d89ab8f343c134616d72eebfe03798835058e2ab579dcc8353c06/httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:474d3b7ab469fefcca3697a10d11a32ee2b9573250206ba1e50d5980910da657", size = 206521, upload-time = "2025-10-10T03:54:31.002Z" }, + { url = "https://files.pythonhosted.org/packages/aa/06/c9c1b41ff52f16aee526fd10fbda99fa4787938aa776858ddc4a1ea825ec/httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3c3b7366bb6c7b96bd72d0dbe7f7d5eead261361f013be5f6d9590465ea1c70", size = 110375, upload-time = "2025-10-10T03:54:31.941Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cc/10935db22fda0ee34c76f047590ca0a8bd9de531406a3ccb10a90e12ea21/httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:379b479408b8747f47f3b253326183d7c009a3936518cdb70db58cffd369d9df", size = 456621, upload-time = "2025-10-10T03:54:33.176Z" }, + { url = "https://files.pythonhosted.org/packages/0e/84/875382b10d271b0c11aa5d414b44f92f8dd53e9b658aec338a79164fa548/httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad6b591a682dcc6cf1397c3900527f9affef1e55a06c4547264796bbd17cf5e", size = 454954, upload-time = "2025-10-10T03:54:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/30/e1/44f89b280f7e46c0b1b2ccee5737d46b3bb13136383958f20b580a821ca0/httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb844698d11433d2139bbeeb56499102143beb582bd6c194e3ba69c22f25c274", size = 440175, upload-time = "2025-10-10T03:54:35.942Z" }, + { url = "https://files.pythonhosted.org/packages/6f/7e/b9287763159e700e335028bc1824359dc736fa9b829dacedace91a39b37e/httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f65744d7a8bdb4bda5e1fa23e4ba16832860606fcc09d674d56e425e991539ec", size = 440310, upload-time = "2025-10-10T03:54:37.1Z" }, + { url = "https://files.pythonhosted.org/packages/b3/07/5b614f592868e07f5c94b1f301b5e14a21df4e8076215a3bccb830a687d8/httptools-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:135fbe974b3718eada677229312e97f3b31f8a9c8ffa3ae6f565bf808d5b6bcb", size = 86875, upload-time = "2025-10-10T03:54:38.421Z" }, + { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" }, + { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" }, + { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" }, + { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" }, + { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, + { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, + { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, + { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jiter" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload-time = "2026-02-02T12:37:56.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/29/499f8c9eaa8a16751b1c0e45e6f5f1761d180da873d417996cc7bddc8eef/jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096", size = 311157, upload-time = "2026-02-02T12:35:37.758Z" }, + { url = "https://files.pythonhosted.org/packages/50/f6/566364c777d2ab450b92100bea11333c64c38d32caf8dc378b48e5b20c46/jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911", size = 319729, upload-time = "2026-02-02T12:35:39.246Z" }, + { url = "https://files.pythonhosted.org/packages/73/dd/560f13ec5e4f116d8ad2658781646cca91b617ae3b8758d4a5076b278f70/jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701", size = 354766, upload-time = "2026-02-02T12:35:40.662Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0d/061faffcfe94608cbc28a0d42a77a74222bdf5055ccdbe5fd2292b94f510/jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c", size = 362587, upload-time = "2026-02-02T12:35:42.025Z" }, + { url = "https://files.pythonhosted.org/packages/92/c9/c66a7864982fd38a9773ec6e932e0398d1262677b8c60faecd02ffb67bf3/jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4", size = 487537, upload-time = "2026-02-02T12:35:43.459Z" }, + { url = "https://files.pythonhosted.org/packages/6c/86/84eb4352cd3668f16d1a88929b5888a3fe0418ea8c1dfc2ad4e7bf6e069a/jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165", size = 373717, upload-time = "2026-02-02T12:35:44.928Z" }, + { url = "https://files.pythonhosted.org/packages/6e/09/9fe4c159358176f82d4390407a03f506a8659ed13ca3ac93a843402acecf/jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018", size = 362683, upload-time = "2026-02-02T12:35:46.636Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5e/85f3ab9caca0c1d0897937d378b4a515cae9e119730563572361ea0c48ae/jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411", size = 392345, upload-time = "2026-02-02T12:35:48.088Z" }, + { url = "https://files.pythonhosted.org/packages/12/4c/05b8629ad546191939e6f0c2f17e29f542a398f4a52fb987bc70b6d1eb8b/jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5", size = 517775, upload-time = "2026-02-02T12:35:49.482Z" }, + { url = "https://files.pythonhosted.org/packages/4d/88/367ea2eb6bc582c7052e4baf5ddf57ebe5ab924a88e0e09830dfb585c02d/jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3", size = 551325, upload-time = "2026-02-02T12:35:51.104Z" }, + { url = "https://files.pythonhosted.org/packages/f3/12/fa377ffb94a2f28c41afaed093e0d70cfe512035d5ecb0cad0ae4792d35e/jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1", size = 204709, upload-time = "2026-02-02T12:35:52.467Z" }, + { url = "https://files.pythonhosted.org/packages/cb/16/8e8203ce92f844dfcd3d9d6a5a7322c77077248dbb12da52d23193a839cd/jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654", size = 204560, upload-time = "2026-02-02T12:35:53.925Z" }, + { url = "https://files.pythonhosted.org/packages/44/26/97cc40663deb17b9e13c3a5cf29251788c271b18ee4d262c8f94798b8336/jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5", size = 189608, upload-time = "2026-02-02T12:35:55.304Z" }, + { url = "https://files.pythonhosted.org/packages/2e/30/7687e4f87086829955013ca12a9233523349767f69653ebc27036313def9/jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663", size = 307958, upload-time = "2026-02-02T12:35:57.165Z" }, + { url = "https://files.pythonhosted.org/packages/c3/27/e57f9a783246ed95481e6749cc5002a8a767a73177a83c63ea71f0528b90/jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505", size = 318597, upload-time = "2026-02-02T12:35:58.591Z" }, + { url = "https://files.pythonhosted.org/packages/cf/52/e5719a60ac5d4d7c5995461a94ad5ef962a37c8bf5b088390e6fad59b2ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152", size = 348821, upload-time = "2026-02-02T12:36:00.093Z" }, + { url = "https://files.pythonhosted.org/packages/61/db/c1efc32b8ba4c740ab3fc2d037d8753f67685f475e26b9d6536a4322bcdd/jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726", size = 364163, upload-time = "2026-02-02T12:36:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/55/8a/fb75556236047c8806995671a18e4a0ad646ed255276f51a20f32dceaeec/jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0", size = 483709, upload-time = "2026-02-02T12:36:03.41Z" }, + { url = "https://files.pythonhosted.org/packages/7e/16/43512e6ee863875693a8e6f6d532e19d650779d6ba9a81593ae40a9088ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089", size = 370480, upload-time = "2026-02-02T12:36:04.791Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4c/09b93e30e984a187bc8aaa3510e1ec8dcbdcd71ca05d2f56aac0492453aa/jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93", size = 360735, upload-time = "2026-02-02T12:36:06.994Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1b/46c5e349019874ec5dfa508c14c37e29864ea108d376ae26d90bee238cd7/jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08", size = 391814, upload-time = "2026-02-02T12:36:08.368Z" }, + { url = "https://files.pythonhosted.org/packages/15/9e/26184760e85baee7162ad37b7912797d2077718476bf91517641c92b3639/jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2", size = 513990, upload-time = "2026-02-02T12:36:09.993Z" }, + { url = "https://files.pythonhosted.org/packages/e9/34/2c9355247d6debad57a0a15e76ab1566ab799388042743656e566b3b7de1/jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228", size = 548021, upload-time = "2026-02-02T12:36:11.376Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4a/9f2c23255d04a834398b9c2e0e665382116911dc4d06b795710503cdad25/jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394", size = 203024, upload-time = "2026-02-02T12:36:12.682Z" }, + { url = "https://files.pythonhosted.org/packages/09/ee/f0ae675a957ae5a8f160be3e87acea6b11dc7b89f6b7ab057e77b2d2b13a/jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92", size = 205424, upload-time = "2026-02-02T12:36:13.93Z" }, + { url = "https://files.pythonhosted.org/packages/1b/02/ae611edf913d3cbf02c97cdb90374af2082c48d7190d74c1111dde08bcdd/jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9", size = 186818, upload-time = "2026-02-02T12:36:15.308Z" }, + { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload-time = "2026-02-02T12:36:16.748Z" }, + { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload-time = "2026-02-02T12:36:18.351Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload-time = "2026-02-02T12:36:19.746Z" }, + { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload-time = "2026-02-02T12:36:21.243Z" }, + { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload-time = "2026-02-02T12:36:22.688Z" }, + { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload-time = "2026-02-02T12:36:24.106Z" }, + { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload-time = "2026-02-02T12:36:25.519Z" }, + { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload-time = "2026-02-02T12:36:26.866Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload-time = "2026-02-02T12:36:28.217Z" }, + { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload-time = "2026-02-02T12:36:29.678Z" }, + { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload-time = "2026-02-02T12:36:31.808Z" }, + { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload-time = "2026-02-02T12:36:33.679Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload-time = "2026-02-02T12:36:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload-time = "2026-02-02T12:36:36.579Z" }, + { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload-time = "2026-02-02T12:36:38.058Z" }, + { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload-time = "2026-02-02T12:36:39.417Z" }, + { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload-time = "2026-02-02T12:36:40.791Z" }, + { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload-time = "2026-02-02T12:36:42.077Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/3c29819a27178d0e461a8571fb63c6ae38be6dc36b78b3ec2876bbd6a910/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c", size = 307016, upload-time = "2026-02-02T12:37:42.755Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ae/60993e4b07b1ac5ebe46da7aa99fdbb802eb986c38d26e3883ac0125c4e0/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2", size = 305024, upload-time = "2026-02-02T12:37:44.774Z" }, + { url = "https://files.pythonhosted.org/packages/77/fa/2227e590e9cf98803db2811f172b2d6460a21539ab73006f251c66f44b14/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434", size = 339337, upload-time = "2026-02-02T12:37:46.668Z" }, + { url = "https://files.pythonhosted.org/packages/2d/92/015173281f7eb96c0ef580c997da8ef50870d4f7f4c9e03c845a1d62ae04/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d", size = 346395, upload-time = "2026-02-02T12:37:48.09Z" }, + { url = "https://files.pythonhosted.org/packages/80/60/e50fa45dd7e2eae049f0ce964663849e897300433921198aef94b6ffa23a/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a", size = 305169, upload-time = "2026-02-02T12:37:50.376Z" }, + { url = "https://files.pythonhosted.org/packages/d2/73/a009f41c5eed71c49bec53036c4b33555afcdee70682a18c6f66e396c039/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f", size = 303808, upload-time = "2026-02-02T12:37:52.092Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/528b439290763bff3d939268085d03382471b442f212dca4ff5f12802d43/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59", size = 337384, upload-time = "2026-02-02T12:37:53.582Z" }, + { url = "https://files.pythonhosted.org/packages/67/8a/a342b2f0251f3dac4ca17618265d93bf244a2a4d089126e81e4c1056ac50/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19", size = 343768, upload-time = "2026-02-02T12:37:55.055Z" }, +] + +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpointer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, +] + +[[package]] +name = "jsonpath-ng" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/32/58/250751940d75c8019659e15482d548a4aa3b6ce122c515102a4bfdac50e3/jsonpath_ng-1.8.0.tar.gz", hash = "sha256:54252968134b5e549ea5b872f1df1168bd7defe1a52fed5a358c194e1943ddc3", size = 74513, upload-time = "2026-02-24T14:42:06.182Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/99/33c7d78a3fb70d545fd5411ac67a651c81602cc09c9cf0df383733f068c5/jsonpath_ng-1.8.0-py3-none-any.whl", hash = "sha256:b8dde192f8af58d646fc031fac9c99fe4d00326afc4148f1f043c601a8cfe138", size = 67844, upload-time = "2026-02-28T00:53:19.637Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" }, + { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" }, + { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" }, + { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" }, + { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" }, + { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" }, + { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" }, + { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" }, + { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" }, + { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" }, + { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" }, + { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" }, + { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, + { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, + { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, + { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, + { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, + { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, + { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, + { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, + { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" }, +] + +[[package]] +name = "langchain" +version = "1.2.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/22/a4d4ac98fc2e393537130bbfba0d71a8113e6f884d96f935923e247397fe/langchain-1.2.10.tar.gz", hash = "sha256:bdcd7218d9c79a413cf15e106e4eb94408ac0963df9333ccd095b9ed43bf3be7", size = 570071, upload-time = "2026-02-10T14:56:49.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/06/c3394327f815fade875724c0f6cff529777c96a1e17fea066deb997f8cf5/langchain-1.2.10-py3-none-any.whl", hash = "sha256:e07a377204451fffaed88276b8193e894893b1003e25c5bca6539288ccca3698", size = 111738, upload-time = "2026-02-10T14:56:47.985Z" }, +] + +[[package]] +name = "langchain-aws" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "boto3" }, + { name = "langchain-core" }, + { name = "numpy" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/1d/bb306951b1c394b7a27effb8eb6c9ee65dd77fcc4be7c20f76e3299a9e1e/langchain_aws-1.1.0.tar.gz", hash = "sha256:1e2f8570328eae4907c3cf7e900dc68d8034ddc865d9dc96823c9f9d8cccb901", size = 393899, upload-time = "2025-11-24T14:35:24.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/33/91b8d2a7570657b371382b45054142c54165a51706990a5c1b4cc40c0e9a/langchain_aws-1.1.0-py3-none-any.whl", hash = "sha256:8ec074615b42839e035354063717374c32c63f5028ef5221ba073fd5f3ef5e37", size = 152432, upload-time = "2025-11-24T14:35:23.004Z" }, +] + +[[package]] +name = "langchain-classic" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langchain-text-splitters" }, + { name = "langsmith" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/6f/59da67274d8ceea16d0610142af33e348a24750894f08c0688de01504ff2/langchain_classic-1.0.2.tar.gz", hash = "sha256:bbf686613d0051905794f2646ecb6a79fa398db399750a4af039107d93054335", size = 10533928, upload-time = "2026-03-06T20:19:46.176Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/4b/20f040567a0e97b28649b7190967190f3df5188984c80873bcbe69585168/langchain_classic-1.0.2-py3-none-any.whl", hash = "sha256:ae3480f488d2cf778f75e59ce0316b336fe2bcd4f8828aeb1aef1e2f26987d7f", size = 1041471, upload-time = "2026-03-06T20:19:44.568Z" }, +] + +[[package]] +name = "langchain-community" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "dataclasses-json" }, + { name = "httpx-sse" }, + { name = "langchain-classic" }, + { name = "langchain-core" }, + { name = "langsmith" }, + { name = "numpy" }, + { name = "pydantic-settings" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sqlalchemy" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/97/a03585d42b9bdb6fbd935282d6e3348b10322a24e6ce12d0c99eb461d9af/langchain_community-0.4.1.tar.gz", hash = "sha256:f3b211832728ee89f169ddce8579b80a085222ddb4f4ed445a46e977d17b1e85", size = 33241144, upload-time = "2025-10-27T15:20:32.504Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/a4/c4fde67f193401512337456cabc2148f2c43316e445f5decd9f8806e2992/langchain_community-0.4.1-py3-none-any.whl", hash = "sha256:2135abb2c7748a35c84613108f7ebf30f8505b18c3c18305ffaecfc7651f6c6a", size = 2533285, upload-time = "2025-10-27T15:20:30.767Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.2.17" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, + { name = "langsmith" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/93/36226f593df52b871fc24d494c274f3a6b2ac76763a2806e7d35611634a1/langchain_core-1.2.17.tar.gz", hash = "sha256:54aa267f3311e347fb2e50951fe08e53761cebfb999ab80e6748d70525bbe872", size = 836130, upload-time = "2026-03-02T22:47:55.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/90/073f33ab383a62908eca7ea699586dfea280e77182176e33199c80ddf22a/langchain_core-1.2.17-py3-none-any.whl", hash = "sha256:bf6bd6ce503874e9c2da1669a69383e967c3de1ea808921d19a9a6bff1a9fbbe", size = 502727, upload-time = "2026-03-02T22:47:54.537Z" }, +] + +[[package]] +name = "langchain-huggingface" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "langchain-core" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/5b/4910551367de5c6ec246616fcc0ddb0bc6f9e5d353d4a22dcb5ab1f87e60/langchain_huggingface-1.2.1.tar.gz", hash = "sha256:33d52a30a56775380c6b4321b78136a410eb079132a80fe7120ddd4b954b4efa", size = 253106, upload-time = "2026-03-02T18:44:39.163Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/90/a1440bfa467a6dd9025ad80f3c239554de28aec49dacfb369fda92871556/langchain_huggingface-1.2.1-py3-none-any.whl", hash = "sha256:0930c216a457d2c8dc7b39a756c39c567f1d88593bfee2c3441f3ae718435f0f", size = 30924, upload-time = "2026-03-02T18:44:37.745Z" }, +] + +[[package]] +name = "langchain-litellm" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "httpx" }, + { name = "langchain-core" }, + { name = "litellm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/bd/96f2fbaf6274d97b463d787691f1ba9298f977c40361bbfc86f622f793e5/langchain_litellm-0.6.1.tar.gz", hash = "sha256:e1dae0c547ad577235998c40700e88a1fec74741c2e010831feff37d57ecb229", size = 332978, upload-time = "2026-03-01T20:35:33.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/ac/cf509fa91e90fea069e40c8d9fea2f89eb0b0acf8a6e33e76ec17c1fc4f5/langchain_litellm-0.6.1-py3-none-any.whl", hash = "sha256:c62b49b3a151d1cee912ba79156cac120d12e572f4ade27557eaeb37a67d6571", size = 24862, upload-time = "2026-03-01T20:35:34.444Z" }, +] + +[[package]] +name = "langchain-milvus" +version = "0.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "pymilvus" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/21/ecce785a24e61ba2c0f6249a5a68b969ccc053342f933aeab31a3f885f5e/langchain_milvus-0.3.3.tar.gz", hash = "sha256:406c2d88da133741f5cc3e2fea4b36386182b35500205c70d003382ded210e41", size = 35577, upload-time = "2026-01-05T10:01:16.386Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/5d/6a0dac51ca2343332d5de9c79686d54f905d225b173a8e1b03ae6d35982a/langchain_milvus-0.3.3-py3-none-any.whl", hash = "sha256:6e12f15453372dd48836978faa4a149de79c721df3322229ad732a5e628e8e97", size = 38962, upload-time = "2026-01-05T10:01:15.186Z" }, +] + +[[package]] +name = "langchain-nvidia-ai-endpoints" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "filetype" }, + { name = "langchain-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/d1/f72ec11097694e24d93268ab031c7ec56ab4bec1c43ef7814c659f3e2493/langchain_nvidia_ai_endpoints-1.1.0.tar.gz", hash = "sha256:048a3e6d7231365fdb9fff7bcff18ce6a516b25500681f51dcb69c39e82512a0", size = 47433, upload-time = "2026-02-25T21:48:16.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/22/5f07957028f7fa8c3d695934af8e7309bfd5ab43f2a7a756d3c3d6ce44f3/langchain_nvidia_ai_endpoints-1.1.0-py3-none-any.whl", hash = "sha256:eb04251b2b21facf9d6f2e6e7fa593b89e4f5023ebe3af1e02813512d1cd9687", size = 51514, upload-time = "2026-02-25T21:48:15.695Z" }, +] + +[[package]] +name = "langchain-openai" +version = "1.1.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "openai" }, + { name = "tiktoken" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/0f/01147f842499338ae3b0dd0a351fb83006d9ed623cf3a999bd68ba5bbe2d/langchain_openai-1.1.10.tar.gz", hash = "sha256:ca6fae7cf19425acc81814efed59c7d205ec9a1f284fd1d08aae9bda85d6501b", size = 1059755, upload-time = "2026-02-17T18:03:44.506Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/17/3785cbcdc81c451179247e4176d2697879cb4f45ab2c59d949ca574e072d/langchain_openai-1.1.10-py3-none-any.whl", hash = "sha256:d91b2c09e9fbc70f7af45345d3aa477744962d41c73a029beb46b4f83b824827", size = 87205, upload-time = "2026-02-17T18:03:43.502Z" }, +] + +[[package]] +name = "langchain-tavily" +version = "0.2.17" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "langchain" }, + { name = "langchain-core" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e6/32/f7b5487efbcd5fca5d4095f03dce7dcf0301ed81b2505d9888427c03619b/langchain_tavily-0.2.17.tar.gz", hash = "sha256:738abd790c50f19565023ad279c8e47e87e1aeb971797fec30a614b418ae6503", size = 25298, upload-time = "2026-01-18T13:09:04.112Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/f9/bb6f1cea2a19215e4169a3bcec3af707ff947cf62f6ef7d28e7280f03e29/langchain_tavily-0.2.17-py3-none-any.whl", hash = "sha256:da4e5e7e328d054dc70a9c934afa1d1e62038612106647ff81ad8bfbe3622256", size = 30734, upload-time = "2026-01-18T13:09:03.1Z" }, +] + +[[package]] +name = "langchain-text-splitters" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/38/14121ead61e0e75f79c3a35e5148ac7c2fe754a55f76eab3eed573269524/langchain_text_splitters-1.1.1.tar.gz", hash = "sha256:34861abe7c07d9e49d4dc852d0129e26b32738b60a74486853ec9b6d6a8e01d2", size = 279352, upload-time = "2026-02-18T23:02:42.798Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/66/d9e0c3b83b0ad75ee746c51ba347cacecb8d656b96e1d513f3e334d1ccab/langchain_text_splitters-1.1.1-py3-none-any.whl", hash = "sha256:5ed0d7bf314ba925041e7d7d17cd8b10f688300d5415fb26c29442f061e329dc", size = 35734, upload-time = "2026-02-18T23:02:41.913Z" }, +] + +[[package]] +name = "langgraph" +version = "1.0.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, + { name = "langgraph-prebuilt" }, + { name = "langgraph-sdk" }, + { name = "pydantic" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/92/14df6fefba28c10caf1cb05aa5b8c7bf005838fe32a86d903b6c7cc4018d/langgraph-1.0.10.tar.gz", hash = "sha256:73bd10ee14a8020f31ef07e9cd4c1a70c35cc07b9c2b9cd637509a10d9d51e29", size = 511644, upload-time = "2026-02-27T21:04:38.743Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/60/260e0c04620a37ba8916b712766c341cc5fc685dabc6948c899494bbc2ae/langgraph-1.0.10-py3-none-any.whl", hash = "sha256:7c298bef4f6ea292fcf9824d6088fe41a6727e2904ad6066f240c4095af12247", size = 160920, upload-time = "2026-02-27T21:04:35.932Z" }, +] + +[[package]] +name = "langgraph-checkpoint" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "ormsgpack" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/44/a8df45d1e8b4637e29789fa8bae1db022c953cc7ac80093cfc52e923547e/langgraph_checkpoint-4.0.1.tar.gz", hash = "sha256:b433123735df11ade28829e40ce25b9be614930cd50245ff2af60629234befd9", size = 158135, upload-time = "2026-02-27T21:06:16.092Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl", hash = "sha256:e3adcd7a0e0166f3b48b8cf508ce0ea366e7420b5a73aa81289888727769b034", size = 50453, upload-time = "2026-02-27T21:06:14.293Z" }, +] + +[[package]] +name = "langgraph-prebuilt" +version = "1.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/06/dd61a5c2dce009d1b03b1d56f2a85b3127659fdddf5b3be5d8f1d60820fb/langgraph_prebuilt-1.0.8.tar.gz", hash = "sha256:0cd3cf5473ced8a6cd687cc5294e08d3de57529d8dd14fdc6ae4899549efcf69", size = 164442, upload-time = "2026-02-19T18:14:39.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/41/ec966424ad3f2ed3996d24079d3342c8cd6c0bd0653c12b2a917a685ec6c/langgraph_prebuilt-1.0.8-py3-none-any.whl", hash = "sha256:d16a731e591ba4470f3e313a319c7eee7dbc40895bcf15c821f985a3522a7ce0", size = 35648, upload-time = "2026-02-19T18:14:37.611Z" }, +] + +[[package]] +name = "langgraph-sdk" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/bd/ca8ae5c6a34be6d4f7aa86016e010ff96b3a939456041565797952e3014d/langgraph_sdk-0.3.9.tar.gz", hash = "sha256:8be8958529b3f6d493ec248fdb46e539362efda75784654a42a7091d22504e0e", size = 184287, upload-time = "2026-02-24T18:39:03.276Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/4c/7a7510260fbda788efd13bf4650d3e7d80988118441ac811ec78e0aa03ac/langgraph_sdk-0.3.9-py3-none-any.whl", hash = "sha256:94654294250c920789b6ed0d8a70c0117fed5736b61efc24ff647157359453c5", size = 90511, upload-time = "2026-02-24T18:39:02.012Z" }, +] + +[[package]] +name = "langsmith" +version = "0.7.14" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "uuid-utils" }, + { name = "xxhash" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/32/b3931027ff7d635a66a0edbeec9f8a285fe77b04f1f0cbbc58fd20f2555a/langsmith-0.7.14.tar.gz", hash = "sha256:95606314a8dea0ea1ff3650da4cf0433737b14c4c296579c6b770b43cb5e0b37", size = 1113666, upload-time = "2026-03-06T20:13:17.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/4f/b81ee2d06e1d69aa689b43d2b777901c060d257507806cad7cd9035d5ca4/langsmith-0.7.14-py3-none-any.whl", hash = "sha256:754dcb474a3f3f83cfefbd9694b897bce2a1a0b412bf75e256f85a64206ddcb7", size = 347350, upload-time = "2026-03-06T20:13:15.706Z" }, +] + +[[package]] +name = "litellm" +version = "1.82.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "click" }, + { name = "fastuuid" }, + { name = "httpx" }, + { name = "importlib-metadata" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "tiktoken" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/00/49bb5c28e0dea0f5086229a2a08d5fdc6c8dc0d8e2acb2a2d1f7dd9f4b70/litellm-1.82.0.tar.gz", hash = "sha256:d388f52447daccbcaafa19a3e68d17b75f1374b5bf2cde680d65e1cd86e50d22", size = 16800355, upload-time = "2026-03-01T02:35:30.363Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/89/eb28bfcf97d6b045c400e72eb047c381594467048c237dbb6c227764084c/litellm-1.82.0-py3-none-any.whl", hash = "sha256:5496b5d4532cccdc7a095c21cbac4042f7662021c57bc1d17be4e39838929e80", size = 14911978, upload-time = "2026-03-01T02:35:26.844Z" }, +] + +[[package]] +name = "locket" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/83/97b29fe05cb6ae28d2dbd30b81e2e402a3eed5f460c26e9eaa5895ceacf5/locket-1.0.0.tar.gz", hash = "sha256:5c0d4c052a8bbbf750e056a8e65ccd309086f4f0f18a2eac306a8dfa4112a632", size = 4350, upload-time = "2022-04-20T22:04:44.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl", hash = "sha256:b6c819a722f7b6bd955b80781788e4a66a55628b858d347536b7e81325a3a5e3", size = 4398, upload-time = "2022-04-20T22:04:42.23Z" }, +] + +[[package]] +name = "mako" +version = "1.3.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, +] + +[[package]] +name = "marshmallow" +version = "3.26.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/79/de6c16cc902f4fc372236926b0ce2ab7845268dcc30fb2fbb7f71b418631/marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57", size = 222095, upload-time = "2025-12-22T06:53:53.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73", size = 50964, upload-time = "2025-12-22T06:53:51.801Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/86/de7e3a1cdcfc941483af70609edc06b83e7c8a0e0dc9ac325200a3f4d220/matplotlib-3.10.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6be43b667360fef5c754dda5d25a32e6307a03c204f3c0fc5468b78fa87b4160", size = 8251215, upload-time = "2025-12-10T22:55:16.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/14/baad3222f424b19ce6ad243c71de1ad9ec6b2e4eb1e458a48fdc6d120401/matplotlib-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2b336e2d91a3d7006864e0990c83b216fcdca64b5a6484912902cef87313d78", size = 8139625, upload-time = "2025-12-10T22:55:17.712Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efb30e3baaea72ce5928e32bab719ab4770099079d66726a62b11b1ef7273be4", size = 8712614, upload-time = "2025-12-10T22:55:20.8Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f4/b8347351da9a5b3f41e26cf547252d861f685c6867d179a7c9d60ad50189/matplotlib-3.10.8-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d56a1efd5bfd61486c8bc968fa18734464556f0fb8e51690f4ac25d85cbbbbc2", size = 9540997, upload-time = "2025-12-10T22:55:23.258Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/c7b914e297efe0bc36917bf216b2acb91044b91e930e878ae12981e461e5/matplotlib-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238b7ce5717600615c895050239ec955d91f321c209dd110db988500558e70d6", size = 9596825, upload-time = "2025-12-10T22:55:25.217Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d3/a4bbc01c237ab710a1f22b4da72f4ff6d77eb4c7735ea9811a94ae239067/matplotlib-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:18821ace09c763ec93aef5eeff087ee493a24051936d7b9ebcad9662f66501f9", size = 8135090, upload-time = "2025-12-10T22:55:27.162Z" }, + { url = "https://files.pythonhosted.org/packages/89/dd/a0b6588f102beab33ca6f5218b31725216577b2a24172f327eaf6417d5c9/matplotlib-3.10.8-cp311-cp311-win_arm64.whl", hash = "sha256:bab485bcf8b1c7d2060b4fcb6fc368a9e6f4cd754c9c2fea281f4be21df394a2", size = 8012377, upload-time = "2025-12-10T22:55:29.185Z" }, + { url = "https://files.pythonhosted.org/packages/9e/67/f997cdcbb514012eb0d10cd2b4b332667997fb5ebe26b8d41d04962fa0e6/matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a", size = 8260453, upload-time = "2025-12-10T22:55:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/7e/65/07d5f5c7f7c994f12c768708bd2e17a4f01a2b0f44a1c9eccad872433e2e/matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58", size = 8148321, upload-time = "2025-12-10T22:55:33.265Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f3/c5195b1ae57ef85339fd7285dfb603b22c8b4e79114bae5f4f0fcf688677/matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04", size = 8716944, upload-time = "2025-12-10T22:55:34.922Z" }, + { url = "https://files.pythonhosted.org/packages/00/f9/7638f5cc82ec8a7aa005de48622eecc3ed7c9854b96ba15bd76b7fd27574/matplotlib-3.10.8-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24d50994d8c5816ddc35411e50a86ab05f575e2530c02752e02538122613371f", size = 9550099, upload-time = "2025-12-10T22:55:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/78cd5920d35b29fd2a0fe894de8adf672ff52939d2e9b43cb83cd5ce1bc7/matplotlib-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99eefd13c0dc3b3c1b4d561c1169e65fe47aab7b8158754d7c084088e2329466", size = 9613040, upload-time = "2025-12-10T22:55:38.715Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/c10f171b6e2f44d9e3a2b96efa38b1677439d79c99357600a62cc1e9594e/matplotlib-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:dd80ecb295460a5d9d260df63c43f4afbdd832d725a531f008dad1664f458adf", size = 8142717, upload-time = "2025-12-10T22:55:41.103Z" }, + { url = "https://files.pythonhosted.org/packages/f1/76/934db220026b5fef85f45d51a738b91dea7d70207581063cd9bd8fafcf74/matplotlib-3.10.8-cp312-cp312-win_arm64.whl", hash = "sha256:3c624e43ed56313651bc18a47f838b60d7b8032ed348911c54906b130b20071b", size = 8012751, upload-time = "2025-12-10T22:55:42.684Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6", size = 8261076, upload-time = "2025-12-10T22:55:44.648Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1", size = 8148794, upload-time = "2025-12-10T22:55:46.252Z" }, + { url = "https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486", size = 8718474, upload-time = "2025-12-10T22:55:47.864Z" }, + { url = "https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce", size = 9549637, upload-time = "2025-12-10T22:55:50.048Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8dc289776eae5109e268c4fb92baf870678dc048a25d4ac903683b86d5bf/matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6", size = 9613678, upload-time = "2025-12-10T22:55:52.21Z" }, + { url = "https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149", size = 8142686, upload-time = "2025-12-10T22:55:54.253Z" }, + { url = "https://files.pythonhosted.org/packages/66/52/8d8a8730e968185514680c2a6625943f70269509c3dcfc0dcf7d75928cb8/matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645", size = 8012917, upload-time = "2025-12-10T22:55:56.268Z" }, + { url = "https://files.pythonhosted.org/packages/b5/27/51fe26e1062f298af5ef66343d8ef460e090a27fea73036c76c35821df04/matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077", size = 8305679, upload-time = "2025-12-10T22:55:57.856Z" }, + { url = "https://files.pythonhosted.org/packages/2c/1e/4de865bc591ac8e3062e835f42dd7fe7a93168d519557837f0e37513f629/matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22", size = 8198336, upload-time = "2025-12-10T22:55:59.371Z" }, + { url = "https://files.pythonhosted.org/packages/c6/cb/2f7b6e75fb4dce87ef91f60cac4f6e34f4c145ab036a22318ec837971300/matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39", size = 8731653, upload-time = "2025-12-10T22:56:01.032Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/bd9c57d6ba670a37ab31fb87ec3e8691b947134b201f881665b28cc039ff/matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565", size = 9561356, upload-time = "2025-12-10T22:56:02.95Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000, upload-time = "2025-12-10T22:56:05.411Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043, upload-time = "2025-12-10T22:56:07.551Z" }, + { url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075, upload-time = "2025-12-10T22:56:09.178Z" }, + { url = "https://files.pythonhosted.org/packages/04/30/3afaa31c757f34b7725ab9d2ba8b48b5e89c2019c003e7d0ead143aabc5a/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6da7c2ce169267d0d066adcf63758f0604aa6c3eebf67458930f9d9b79ad1db1", size = 8249198, upload-time = "2025-12-10T22:56:45.584Z" }, + { url = "https://files.pythonhosted.org/packages/48/2f/6334aec331f57485a642a7c8be03cb286f29111ae71c46c38b363230063c/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9153c3292705be9f9c64498a8872118540c3f4123d1a1c840172edf262c8be4a", size = 8136817, upload-time = "2025-12-10T22:56:47.339Z" }, + { url = "https://files.pythonhosted.org/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867, upload-time = "2025-12-10T22:56:48.954Z" }, +] + +[[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 = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "msgpack" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, + { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" }, + { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" }, + { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" }, + { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" }, + { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" }, + { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" }, + { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" }, + { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" }, + { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, + { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, + { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, + { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, + { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +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/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/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 = "multiprocess" +version = "0.70.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/4d/9af0d1279c84618bcd35bf5fd7e371657358c7b0a523e54a9cffb87461f8/multiprocess-0.70.18-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b8940ae30139e04b076da6c5b83e9398585ebdf0f2ad3250673fef5b2ff06d6", size = 144695, upload-time = "2025-04-17T03:11:09.161Z" }, + { url = "https://files.pythonhosted.org/packages/17/bf/87323e79dd0562474fad3373c21c66bc6c3c9963b68eb2a209deb4c8575e/multiprocess-0.70.18-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0929ba95831adb938edbd5fb801ac45e705ecad9d100b3e653946b7716cb6bd3", size = 144742, upload-time = "2025-04-17T03:11:10.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/74/cb8c831e58dc6d5cf450b17c7db87f14294a1df52eb391da948b5e0a0b94/multiprocess-0.70.18-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4d77f8e4bfe6c6e2e661925bbf9aed4d5ade9a1c6502d5dfc10129b9d1141797", size = 144745, upload-time = "2025-04-17T03:11:11.453Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/4b/88/9039f2fed1012ef584751d4ceff9ab4a51e5ae264898f0b7cbf44340a859/multiprocess-0.70.18-py311-none-any.whl", hash = "sha256:5aa6eef98e691281b3ad923be2832bf1c55dd2c859acd73e5ec53a66aae06a1d", size = 144462, upload-time = "2025-04-17T03:11:21.657Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b6/5f922792be93b82ec6b5f270bbb1ef031fd0622847070bbcf9da816502cc/multiprocess-0.70.18-py312-none-any.whl", hash = "sha256:9b78f8e5024b573730bfb654783a13800c2c0f2dfc0c25e70b40d184d64adaa2", size = 150287, upload-time = "2025-04-17T03:11:22.69Z" }, + { url = "https://files.pythonhosted.org/packages/ee/25/7d7e78e750bc1aecfaf0efbf826c69a791d2eeaf29cf20cba93ff4cced78/multiprocess-0.70.18-py313-none-any.whl", hash = "sha256:871743755f43ef57d7910a38433cfe41319e72be1bbd90b79c7a5ac523eb9334", size = 151917, upload-time = "2025-04-17T03:11:24.044Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "narwhals" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/59/81d0f4cad21484083466f278e6b392addd9f4205b48d45b5c8771670ebf8/narwhals-2.17.0.tar.gz", hash = "sha256:ebd5bc95bcfa2f8e89a8ac09e2765a63055162837208e67b42d6eeb6651d5e67", size = 620306, upload-time = "2026-02-23T09:44:34.142Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/27/20770bd6bf8fbe1e16f848ba21da9df061f38d2e6483952c29d2bb5d1d8b/narwhals-2.17.0-py3-none-any.whl", hash = "sha256:2ac5307b7c2b275a7d66eeda906b8605e3d7a760951e188dcfff86e8ebe083dd", size = 444897, upload-time = "2026-02-23T09:44:32.006Z" }, +] + +[[package]] +name = "nemo-evaluator" +version = "0.1.95" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flask" }, + { name = "httpx" }, + { name = "jinja2" }, + { name = "psutil" }, + { name = "pydantic" }, + { name = "pydantic-core" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "structlog" }, + { name = "typing-extensions" }, + { name = "werkzeug" }, + { name = "yq" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/d7/435c316dd105567aeba3717dec50ce0fa6c74d1ad41cf2388cd394310119/nemo_evaluator-0.1.95.tar.gz", hash = "sha256:0d5c771697077587b31f6818f29b8544f0a05ea134ee8877d2d48f4007beec16", size = 150232, upload-time = "2026-03-05T01:38:01.264Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/02/493061480914ed3494cf96ae81757a96a01615d909c94c24d48ec34fef57/nemo_evaluator-0.1.95-py3-none-any.whl", hash = "sha256:22fa6f36b53b19d1faa135115e3208eebc129767846fea7da1788a0d729cb755", size = 197442, upload-time = "2026-03-05T01:37:58.331Z" }, +] + +[[package]] +name = "nest-asyncio2" +version = "1.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/73/731debf26e27e0a0323d7bda270dc2f634b398e38f040a09da1f4351d0aa/nest_asyncio2-1.7.2.tar.gz", hash = "sha256:1921d70b92cc4612c374928d081552efb59b83d91b2b789d935c665fa01729a8", size = 14743, upload-time = "2026-02-13T00:34:04.386Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/3c/3179b85b0e1c3659f0369940200cd6d0fa900e6cefcc7ea0bc6dd0e29ffb/nest_asyncio2-1.7.2-py3-none-any.whl", hash = "sha256:f5dfa702f3f81f6a03857e9a19e2ba578c0946a4ad417b4c50a24d7ba641fe01", size = 7843, upload-time = "2026-02-13T00:34:02.691Z" }, +] + +[[package]] +name = "networkx" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" }, + { url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" }, + { url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" }, + { url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" }, + { url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" }, + { url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" }, + { url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" }, + { url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" }, + { url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" }, + { url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" }, + { url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" }, + { url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" }, + { url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" }, + { url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" }, + { url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" }, + { url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" }, + { url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" }, + { url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" }, + { url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" }, + { url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" }, + { url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" }, + { url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" }, + { url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" }, + { url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" }, + { url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" }, + { url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" }, + { url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" }, + { url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" }, + { url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" }, + { url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" }, + { url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" }, + { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, +] + +[[package]] +name = "nvidia-nat-benchmarks" +source = { editable = "." } +dependencies = [ + { name = "nvidia-nat-core" }, + { name = "nvidia-nat-eval" }, + { name = "nvidia-nat-langchain" }, +] + +[package.optional-dependencies] +agent-leaderboard = [ + { name = "datasets" }, +] +all = [ + { name = "datasets" }, + { name = "nemo-evaluator" }, + { name = "nvidia-tooltalk" }, + { name = "tree-sitter" }, + { name = "tree-sitter-java" }, + { name = "tree-sitter-javascript" }, +] +bfcl = [ + { name = "tree-sitter" }, + { name = "tree-sitter-java" }, + { name = "tree-sitter-javascript" }, +] +byob = [ + { name = "nemo-evaluator" }, +] +test = [ + { name = "datasets" }, + { name = "nemo-evaluator" }, + { name = "nvidia-nat-core", extra = ["async-endpoints"] }, + { name = "nvidia-nat-test" }, + { name = "nvidia-tooltalk" }, + { name = "tree-sitter" }, + { name = "tree-sitter-java" }, + { name = "tree-sitter-javascript" }, +] +tooltalk = [ + { name = "nvidia-tooltalk" }, +] + +[package.metadata] +requires-dist = [ + { name = "datasets", marker = "extra == 'agent-leaderboard'", specifier = "~=4.4" }, + { name = "nemo-evaluator", marker = "extra == 'byob'", specifier = "~=0.1" }, + { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard", "bfcl", "byob", "tooltalk"], marker = "extra == 'all'", specifier = "==1.6.0.dev51+gab4c3030" }, + { name = "nvidia-nat-benchmarks", extras = ["all"], marker = "extra == 'test'", specifier = "==1.6.0.dev51+gab4c3030" }, + { name = "nvidia-nat-core", editable = "../nvidia_nat_core" }, + { name = "nvidia-nat-core", extras = ["async-endpoints"], marker = "extra == 'test'", editable = "../nvidia_nat_core" }, + { name = "nvidia-nat-eval", editable = "../nvidia_nat_eval" }, + { name = "nvidia-nat-langchain", editable = "../nvidia_nat_langchain" }, + { name = "nvidia-nat-test", marker = "extra == 'test'", editable = "../nvidia_nat_test" }, + { name = "nvidia-tooltalk", marker = "extra == 'tooltalk'", specifier = "~=26.1" }, + { name = "tree-sitter", marker = "extra == 'bfcl'", specifier = "~=0.21.0" }, + { name = "tree-sitter-java", marker = "extra == 'bfcl'", specifier = "~=0.21.0" }, + { name = "tree-sitter-javascript", marker = "extra == 'bfcl'", specifier = "~=0.21.0" }, +] +provides-extras = ["tooltalk", "bfcl", "byob", "agent-leaderboard", "all", "test"] + +[[package]] +name = "nvidia-nat-core" +source = { editable = "../nvidia_nat_core" } +dependencies = [ + { name = "aioboto3" }, + { name = "authlib" }, + { name = "click" }, + { name = "colorama" }, + { name = "expandvars" }, + { name = "fastapi" }, + { name = "flask" }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "jinja2" }, + { name = "jsonpath-ng" }, + { name = "nest-asyncio2" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "openinference-semantic-conventions" }, + { name = "optuna" }, + { name = "pandas" }, + { name = "pip" }, + { name = "pkce" }, + { name = "pkginfo" }, + { name = "platformdirs" }, + { name = "plotly" }, + { name = "pydantic" }, + { name = "pyjwt" }, + { name = "pymilvus" }, + { name = "python-dotenv" }, + { name = "python-multipart" }, + { name = "pyyaml" }, + { name = "rich" }, + { name = "starlette" }, + { name = "tabulate" }, + { name = "tzlocal" }, + { name = "urllib3" }, + { name = "uvicorn", extra = ["standard"] }, + { name = "wikipedia" }, +] + +[package.optional-dependencies] +async-endpoints = [ + { name = "aiosqlite" }, + { name = "dask" }, + { name = "distributed" }, + { name = "sqlalchemy", extra = ["asyncio"] }, +] + +[package.metadata] +requires-dist = [ + { name = "aioboto3", specifier = ">=11.0.0" }, + { name = "aiosqlite", marker = "extra == 'async-endpoints'", specifier = "~=0.21" }, + { name = "authlib", specifier = ">=1.6.5,<2.0.0" }, + { name = "click", specifier = "~=8.1" }, + { name = "colorama", specifier = ">=0.4.6,<1.0.0" }, + { name = "dask", marker = "extra == 'async-endpoints'", specifier = "~=2026.1" }, + { name = "distributed", marker = "extra == 'async-endpoints'", specifier = "~=2026.1" }, + { name = "expandvars", specifier = "~=1.0" }, + { name = "fastapi", specifier = "~=0.119" }, + { name = "flask", specifier = ">=3.0.0" }, + { name = "gunicorn", marker = "extra == 'gunicorn'", specifier = "~=23.0" }, + { name = "httpx", specifier = "~=0.27" }, + { name = "huggingface-hub", specifier = ">=0.33.4,<1.0.0" }, + { name = "jinja2", specifier = "~=3.1" }, + { name = "jsonpath-ng", specifier = "~=1.7" }, + { name = "nest-asyncio2", specifier = "~=1.7" }, + { name = "networkx", specifier = "~=3.4" }, + { name = "numpy", specifier = "~=2.3" }, + { name = "nvidia-nat-eval", extras = ["profiling"], marker = "extra == 'test'", editable = "../nvidia_nat_eval" }, + { name = "nvidia-nat-test", marker = "extra == 'test'", editable = "../nvidia_nat_test" }, + { name = "openinference-semantic-conventions", specifier = ">=0.1.14,<1.0.0" }, + { name = "optuna", specifier = "~=4.4" }, + { name = "pandas", specifier = "~=2.2" }, + { name = "pip", specifier = ">=24.3.1" }, + { name = "pkce", specifier = "==1.0.3" }, + { name = "pkginfo", specifier = "~=1.12" }, + { name = "platformdirs", specifier = "~=4.3" }, + { name = "plotly", specifier = "~=6.0" }, + { name = "presidio-analyzer", marker = "extra == 'pii-defense'" }, + { name = "presidio-anonymizer", marker = "extra == 'pii-defense'" }, + { name = "pydantic", specifier = "~=2.11" }, + { name = "pyjwt", specifier = "~=2.11" }, + { name = "pymilvus", specifier = "~=2.6" }, + { name = "python-dotenv", specifier = ">=1.1.1,<2.0.0" }, + { name = "python-multipart", specifier = ">=0.0.21" }, + { name = "pyyaml", specifier = "~=6.0" }, + { name = "rich", specifier = "~=14.0" }, + { name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'async-endpoints'", specifier = "~=2.0" }, + { name = "starlette", specifier = "~=0.51" }, + { name = "tabulate", specifier = "~=0.9" }, + { name = "tzlocal", specifier = "~=5.3" }, + { name = "urllib3", specifier = ">=2.6.3,<3.0.0" }, + { name = "uvicorn", extras = ["standard"], specifier = "~=0.38" }, + { name = "wikipedia", specifier = "~=1.4" }, +] +provides-extras = ["async-endpoints", "gunicorn", "pii-defense", "test"] + +[[package]] +name = "nvidia-nat-eval" +source = { editable = "../nvidia_nat_eval" } +dependencies = [ + { name = "datasets" }, + { name = "nvidia-nat-core" }, + { name = "openpyxl" }, +] + +[package.metadata] +requires-dist = [ + { name = "datasets", specifier = "~=4.4" }, + { name = "nvidia-nat-core", editable = "../nvidia_nat_core" }, + { name = "nvidia-nat-core", extras = ["async-endpoints"], marker = "extra == 'test'", editable = "../nvidia_nat_core" }, + { name = "nvidia-nat-test", marker = "extra == 'test'", editable = "../nvidia_nat_test" }, + { name = "openpyxl", specifier = "~=3.1" }, +] +provides-extras = ["test"] + +[[package]] +name = "nvidia-nat-langchain" +source = { editable = "../nvidia_nat_langchain" } +dependencies = [ + { name = "langchain" }, + { name = "langchain-aws" }, + { name = "langchain-classic" }, + { name = "langchain-community" }, + { name = "langchain-core" }, + { name = "langchain-huggingface" }, + { name = "langchain-litellm" }, + { name = "langchain-milvus" }, + { name = "langchain-nvidia-ai-endpoints" }, + { name = "langchain-openai" }, + { name = "langchain-tavily" }, + { name = "langgraph" }, + { name = "nvidia-nat-core" }, + { name = "nvidia-nat-eval" }, + { name = "nvidia-nat-opentelemetry" }, + { name = "openevals" }, +] + +[package.metadata] +requires-dist = [ + { name = "langchain", specifier = ">=1.2.3,<2.0.0" }, + { name = "langchain-aws", specifier = ">=1.1.0,<2.0.0" }, + { name = "langchain-classic", specifier = ">=1.0.1,<2.0.0" }, + { name = "langchain-community", specifier = "~=0.3" }, + { name = "langchain-core", specifier = ">=1.2.6,<2.0.0" }, + { name = "langchain-huggingface", specifier = ">=1.2.0,<2.0.0" }, + { name = "langchain-litellm", specifier = ">=0.3.5,<1.0.0" }, + { name = "langchain-milvus", specifier = ">=0.3.3,<1.0.0" }, + { name = "langchain-nvidia-ai-endpoints", specifier = ">=1.0.2,<2.0.0" }, + { name = "langchain-openai", specifier = ">=1.1.6,<2.0.0" }, + { name = "langchain-tavily", specifier = ">=0.2.16,<1.0.0" }, + { name = "langgraph", specifier = ">=1.0.5,<2.0.0" }, + { name = "nvidia-nat-core", editable = "../nvidia_nat_core" }, + { name = "nvidia-nat-eval", editable = "../nvidia_nat_eval" }, + { name = "nvidia-nat-eval", extras = ["profiling"], marker = "extra == 'test'", editable = "../nvidia_nat_eval" }, + { name = "nvidia-nat-opentelemetry", editable = "../nvidia_nat_opentelemetry" }, + { name = "nvidia-nat-test", marker = "extra == 'test'", editable = "../nvidia_nat_test" }, + { name = "openevals", specifier = ">=0.1.3,<1.0.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "nvidia-nat-opentelemetry" +source = { editable = "../nvidia_nat_opentelemetry" } +dependencies = [ + { name = "nvidia-nat-core" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp" }, + { name = "opentelemetry-sdk" }, +] + +[package.metadata] +requires-dist = [ + { name = "nvidia-nat-core", editable = "../nvidia_nat_core" }, + { name = "nvidia-nat-test", marker = "extra == 'test'", editable = "../nvidia_nat_test" }, + { name = "opentelemetry-api", specifier = "~=1.2" }, + { name = "opentelemetry-exporter-otlp", specifier = "~=1.3" }, + { name = "opentelemetry-sdk", specifier = "~=1.3" }, +] +provides-extras = ["test"] + +[[package]] +name = "nvidia-nat-test" +source = { editable = "../nvidia_nat_test" } +dependencies = [ + { name = "asgi-lifespan" }, + { name = "langchain-community" }, + { name = "nvidia-nat-core" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, + { name = "pytest-httpserver" }, + { name = "pytest-timeout" }, +] + +[package.metadata] +requires-dist = [ + { name = "asgi-lifespan", specifier = "~=2.1" }, + { name = "langchain-community", specifier = "~=0.3" }, + { name = "nvidia-nat-core", editable = "../nvidia_nat_core" }, + { name = "pytest", specifier = "~=8.3" }, + { name = "pytest-asyncio", specifier = "==0.24.*" }, + { name = "pytest-cov", specifier = "~=6.1" }, + { name = "pytest-httpserver", specifier = "==1.1.*" }, + { name = "pytest-timeout", specifier = "~=2.4" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, +] + +[[package]] +name = "nvidia-tooltalk" +version = "26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "nemo-evaluator" }, + { name = "numpy" }, + { name = "openai" }, + { name = "pytest" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/81/5cef75e53bddb8f1df42c3b25390cb3a8fcf75569047248cb02bb9721e33/nvidia_tooltalk-26.1-py3-none-any.whl", hash = "sha256:a6bfedbb590e50a55cbcf14bfe430d16e18c020998e0fbb6c8700685bb2442b7", size = 165640, upload-time = "2026-02-27T08:28:30.982Z" }, +] + +[[package]] +name = "openai" +version = "2.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/91/2a06c4e9597c338cac1e5e5a8dd6f29e1836fc229c4c523529dca387fda8/openai-2.26.0.tar.gz", hash = "sha256:b41f37c140ae0034a6e92b0c509376d907f3a66109935fba2c1b471a7c05a8fb", size = 666702, upload-time = "2026-03-05T23:17:35.874Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/2e/3f73e8ca53718952222cacd0cf7eecc9db439d020f0c1fe7ae717e4e199a/openai-2.26.0-py3-none-any.whl", hash = "sha256:6151bf8f83802f036117f06cc8a57b3a4da60da9926826cc96747888b57f394f", size = 1136409, upload-time = "2026-03-05T23:17:34.072Z" }, +] + +[[package]] +name = "openevals" +version = "0.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain" }, + { name = "langchain-openai" }, + { name = "langsmith" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/37/31e23ef661fa4c3c6a3c979afd884b30205512b4dde680b36d5909550500/openevals-0.1.3.tar.gz", hash = "sha256:9b00df1a7738464676aa887d4d950b77d3ef7024f6e8a54be3a83c82f485ea65", size = 100828, upload-time = "2025-12-18T04:09:03.034Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/68/162b0d273ffef5b0ad557ebccb790725bf94d78969702324dd5726828cf0/openevals-0.1.3-py3-none-any.whl", hash = "sha256:aed448df0cfdded732e24cda026eda065435a71ffb8c406a3ce73e590156d9f9", size = 67802, upload-time = "2025-12-18T04:09:01.59Z" }, +] + +[[package]] +name = "openinference-semantic-conventions" +version = "0.1.27" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/cf/7c0ea344b99ecdb9f55cb5287ecb6a6ad68e6098df32728691fa7846f112/openinference_semantic_conventions-0.1.27.tar.gz", hash = "sha256:db0b1bbc1cd66f8108b17f972976fa1833413a01967ff930e2707a77e0f66bd3", size = 12744, upload-time = "2026-03-04T08:38:56.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/b4/1c218ed1e68c8fbd68f37258ce40f908cdad86ee9d38b12c48c9e4c4e030/openinference_semantic_conventions-0.1.27-py3-none-any.whl", hash = "sha256:3871fd2cc9d203bdb444ab66ff2ba9bdbf1013dc48c64c5700dd449d47b338c5", size = 10430, upload-time = "2026-03-04T08:38:56.166Z" }, +] + +[[package]] +name = "openpyxl" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "et-xmlfile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, +] + +[[package]] +name = "opentelemetry-api" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp" +version = "1.40.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/d0/37/b6708e0eff5c5fb9aba2e0ea09f7f3bcbfd12a592d2a780241b5f6014df7/opentelemetry_exporter_otlp-1.40.0.tar.gz", hash = "sha256:7caa0870b95e2fcb59d64e16e2b639ecffb07771b6cd0000b5d12e5e4fef765a", size = 6152, upload-time = "2026-03-04T14:17:23.235Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/fc/aea77c28d9f3ffef2fdafdc3f4a235aee4091d262ddabd25882f47ce5c5f/opentelemetry_exporter_otlp-1.40.0-py3-none-any.whl", hash = "sha256:48c87e539ec9afb30dc443775a1334cc5487de2f72a770a4c00b1610bf6c697d", size = 7023, upload-time = "2026-03-04T14:17:03.612Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-proto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-grpc" +version = "1.40.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/8f/7f/b9e60435cfcc7590fa87436edad6822240dddbc184643a2a005301cc31f4/opentelemetry_exporter_otlp_proto_grpc-1.40.0.tar.gz", hash = "sha256:bd4015183e40b635b3dab8da528b27161ba83bf4ef545776b196f0fb4ec47740", size = 25759, upload-time = "2026-03-04T14:17:24.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/6f/7ee0980afcbdcd2d40362da16f7f9796bd083bf7f0b8e038abfbc0300f5d/opentelemetry_exporter_otlp_proto_grpc-1.40.0-py3-none-any.whl", hash = "sha256:2aa0ca53483fe0cf6405087a7491472b70335bc5c7944378a0a8e72e86995c52", size = 20304, upload-time = "2026-03-04T14:17:05.942Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-http" +version = "1.40.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/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.61b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, +] + +[[package]] +name = "optuna" +version = "4.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alembic" }, + { name = "colorlog" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "sqlalchemy" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/b2/b5e12de7b4486556fe2257611b55dbabf30d0300bdb031831aa943ad20e4/optuna-4.7.0.tar.gz", hash = "sha256:d91817e2079825557bd2e97de2e8c9ae260bfc99b32712502aef8a5095b2d2c0", size = 479740, upload-time = "2026-01-19T05:45:52.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/d1/6c8a4fbb38a9e3565f5c36b871262a85ecab3da48120af036b1e4937a15c/optuna-4.7.0-py3-none-any.whl", hash = "sha256:e41ec84018cecc10eabf28143573b1f0bde0ba56dba8151631a590ecbebc1186", size = 413894, upload-time = "2026-01-19T05:45:50.815Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/02/da6cb01fc6087048d7f61522c327edf4250f1683a58a839fdcc435746dd5/orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c", size = 228664, upload-time = "2026-02-02T15:37:25.542Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c2/5885e7a5881dba9a9af51bc564e8967225a642b3e03d089289a35054e749/orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b", size = 125344, upload-time = "2026-02-02T15:37:26.92Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1d/4e7688de0a92d1caf600dfd5fb70b4c5bfff51dfa61ac555072ef2d0d32a/orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e", size = 128404, upload-time = "2026-02-02T15:37:28.108Z" }, + { url = "https://files.pythonhosted.org/packages/2f/b2/ec04b74ae03a125db7bd69cffd014b227b7f341e3261bf75b5eb88a1aa92/orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5", size = 123677, upload-time = "2026-02-02T15:37:30.287Z" }, + { url = "https://files.pythonhosted.org/packages/4c/69/f95bdf960605f08f827f6e3291fe243d8aa9c5c9ff017a8d7232209184c3/orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62", size = 128950, upload-time = "2026-02-02T15:37:31.595Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1b/de59c57bae1d148ef298852abd31909ac3089cff370dfd4cd84cc99cbc42/orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910", size = 141756, upload-time = "2026-02-02T15:37:32.985Z" }, + { url = "https://files.pythonhosted.org/packages/ee/9e/9decc59f4499f695f65c650f6cfa6cd4c37a3fbe8fa235a0a3614cb54386/orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b", size = 130812, upload-time = "2026-02-02T15:37:34.204Z" }, + { url = "https://files.pythonhosted.org/packages/28/e6/59f932bcabd1eac44e334fe8e3281a92eacfcb450586e1f4bde0423728d8/orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960", size = 133444, upload-time = "2026-02-02T15:37:35.446Z" }, + { url = "https://files.pythonhosted.org/packages/f1/36/b0f05c0eaa7ca30bc965e37e6a2956b0d67adb87a9872942d3568da846ae/orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8", size = 138609, upload-time = "2026-02-02T15:37:36.657Z" }, + { url = "https://files.pythonhosted.org/packages/b8/03/58ec7d302b8d86944c60c7b4b82975d5161fcce4c9bc8c6cb1d6741b6115/orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504", size = 408918, upload-time = "2026-02-02T15:37:38.076Z" }, + { url = "https://files.pythonhosted.org/packages/06/3a/868d65ef9a8b99be723bd510de491349618abd9f62c826cf206d962db295/orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e", size = 143998, upload-time = "2026-02-02T15:37:39.706Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c7/1e18e1c83afe3349f4f6dc9e14910f0ae5f82eac756d1412ea4018938535/orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561", size = 134802, upload-time = "2026-02-02T15:37:41.002Z" }, + { url = "https://files.pythonhosted.org/packages/d4/0b/ccb7ee1a65b37e8eeb8b267dc953561d72370e85185e459616d4345bab34/orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d", size = 127828, upload-time = "2026-02-02T15:37:42.241Z" }, + { url = "https://files.pythonhosted.org/packages/af/9e/55c776dffda3f381e0f07d010a4f5f3902bf48eaba1bb7684d301acd4924/orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471", size = 124941, upload-time = "2026-02-02T15:37:43.444Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/424a620fa7d263b880162505fb107ef5e0afaa765b5b06a88312ac291560/orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d", size = 126245, upload-time = "2026-02-02T15:37:45.18Z" }, + { url = "https://files.pythonhosted.org/packages/80/bf/76f4f1665f6983385938f0e2a5d7efa12a58171b8456c252f3bae8a4cf75/orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f", size = 228545, upload-time = "2026-02-02T15:37:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/79/53/6c72c002cb13b5a978a068add59b25a8bdf2800ac1c9c8ecdb26d6d97064/orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b", size = 125224, upload-time = "2026-02-02T15:37:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/2c/83/10e48852865e5dd151bdfe652c06f7da484578ed02c5fca938e3632cb0b8/orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a", size = 128154, upload-time = "2026-02-02T15:37:48.954Z" }, + { url = "https://files.pythonhosted.org/packages/6e/52/a66e22a2b9abaa374b4a081d410edab6d1e30024707b87eab7c734afe28d/orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10", size = 123548, upload-time = "2026-02-02T15:37:50.187Z" }, + { url = "https://files.pythonhosted.org/packages/de/38/605d371417021359f4910c496f764c48ceb8997605f8c25bf1dfe58c0ebe/orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa", size = 129000, upload-time = "2026-02-02T15:37:51.426Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/af32e842b0ffd2335c89714d48ca4e3917b42f5d6ee5537832e069a4b3ac/orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8", size = 141686, upload-time = "2026-02-02T15:37:52.607Z" }, + { url = "https://files.pythonhosted.org/packages/96/0b/fc793858dfa54be6feee940c1463370ece34b3c39c1ca0aa3845f5ba9892/orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f", size = 130812, upload-time = "2026-02-02T15:37:53.944Z" }, + { url = "https://files.pythonhosted.org/packages/dc/91/98a52415059db3f374757d0b7f0f16e3b5cd5976c90d1c2b56acaea039e6/orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad", size = 133440, upload-time = "2026-02-02T15:37:55.615Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/cb540117bda61791f46381f8c26c8f93e802892830a6055748d3bb1925ab/orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867", size = 138386, upload-time = "2026-02-02T15:37:56.814Z" }, + { url = "https://files.pythonhosted.org/packages/63/1a/50a3201c334a7f17c231eee5f841342190723794e3b06293f26e7cf87d31/orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d", size = 408853, upload-time = "2026-02-02T15:37:58.291Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/8de1c67d0be44fdc22701e5989c0d015a2adf391498ad42c4dc589cd3013/orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab", size = 144130, upload-time = "2026-02-02T15:38:00.163Z" }, + { url = "https://files.pythonhosted.org/packages/0f/fe/d605d700c35dd55f51710d159fc54516a280923cd1b7e47508982fbb387d/orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2", size = 134818, upload-time = "2026-02-02T15:38:01.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e4/15ecc67edb3ddb3e2f46ae04475f2d294e8b60c1825fbe28a428b93b3fbd/orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f", size = 127923, upload-time = "2026-02-02T15:38:02.75Z" }, + { url = "https://files.pythonhosted.org/packages/34/70/2e0855361f76198a3965273048c8e50a9695d88cd75811a5b46444895845/orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74", size = 125007, upload-time = "2026-02-02T15:38:04.032Z" }, + { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/6e0e52cac5aab51d7b6dcd257e855e1dec1c2060f6b28566c509b4665f62/orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733", size = 228390, upload-time = "2026-02-02T15:38:06.8Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/a77f48d2fc8a05bbc529e5ff481fb43d914f9e383ea2469d4f3d51df3d00/orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4", size = 125189, upload-time = "2026-02-02T15:38:08.181Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/0a16e0729a0e6a1504f9d1a13cdd365f030068aab64cec6958396b9969d7/orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785", size = 128106, upload-time = "2026-02-02T15:38:09.41Z" }, + { url = "https://files.pythonhosted.org/packages/66/da/a2e505469d60666a05ab373f1a6322eb671cb2ba3a0ccfc7d4bc97196787/orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539", size = 123363, upload-time = "2026-02-02T15:38:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/ed73f88396ea35c71b38961734ea4a4746f7ca0768bf28fd551d37e48dd0/orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1", size = 129007, upload-time = "2026-02-02T15:38:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/3c/b05d80716f0225fc9008fbf8ab22841dcc268a626aa550561743714ce3bf/orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1", size = 141667, upload-time = "2026-02-02T15:38:13.398Z" }, + { url = "https://files.pythonhosted.org/packages/61/e8/0be9b0addd9bf86abfc938e97441dcd0375d494594b1c8ad10fe57479617/orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705", size = 130832, upload-time = "2026-02-02T15:38:14.698Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ec/c68e3b9021a31d9ec15a94931db1410136af862955854ed5dd7e7e4f5bff/orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace", size = 133373, upload-time = "2026-02-02T15:38:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/45/f3466739aaafa570cc8e77c6dbb853c48bf56e3b43738020e2661e08b0ac/orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b", size = 138307, upload-time = "2026-02-02T15:38:17.453Z" }, + { url = "https://files.pythonhosted.org/packages/e1/84/9f7f02288da1ffb31405c1be07657afd1eecbcb4b64ee2817b6fe0f785fa/orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157", size = 408695, upload-time = "2026-02-02T15:38:18.831Z" }, + { url = "https://files.pythonhosted.org/packages/18/07/9dd2f0c0104f1a0295ffbe912bc8d63307a539b900dd9e2c48ef7810d971/orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3", size = 144099, upload-time = "2026-02-02T15:38:20.28Z" }, + { url = "https://files.pythonhosted.org/packages/a5/66/857a8e4a3292e1f7b1b202883bcdeb43a91566cf59a93f97c53b44bd6801/orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223", size = 134806, upload-time = "2026-02-02T15:38:22.186Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5b/6ebcf3defc1aab3a338ca777214966851e92efb1f30dc7fc8285216e6d1b/orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3", size = 127914, upload-time = "2026-02-02T15:38:23.511Z" }, + { url = "https://files.pythonhosted.org/packages/00/04/c6f72daca5092e3117840a1b1e88dfc809cc1470cf0734890d0366b684a1/orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757", size = 124986, upload-time = "2026-02-02T15:38:24.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/ba/077a0f6f1085d6b806937246860fafbd5b17f3919c70ee3f3d8d9c713f38/orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539", size = 126045, upload-time = "2026-02-02T15:38:26.216Z" }, +] + +[[package]] +name = "ormsgpack" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/0c/f1761e21486942ab9bb6feaebc610fa074f7c5e496e6962dea5873348077/ormsgpack-1.12.2.tar.gz", hash = "sha256:944a2233640273bee67521795a73cf1e959538e0dfb7ac635505010455e53b33", size = 39031, upload-time = "2026-01-18T20:55:28.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/08/8b68f24b18e69d92238aa8f258218e6dfeacf4381d9d07ab8df303f524a9/ormsgpack-1.12.2-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bd5f4bf04c37888e864f08e740c5a573c4017f6fd6e99fa944c5c935fabf2dd9", size = 378266, upload-time = "2026-01-18T20:55:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/29fc13044ecb7c153523ae0a1972269fcd613650d1fa1a9cec1044c6b666/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d5b28b3570e9fed9a5a76528fc7230c3c76333bc214798958e58e9b79cc18a", size = 203035, upload-time = "2026-01-18T20:55:30.59Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c2/00169fb25dd8f9213f5e8a549dfb73e4d592009ebc85fbbcd3e1dcac575b/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3708693412c28f3538fb5a65da93787b6bbab3484f6bc6e935bfb77a62400ae5", size = 210539, upload-time = "2026-01-18T20:55:48.569Z" }, + { url = "https://files.pythonhosted.org/packages/1b/33/543627f323ff3c73091f51d6a20db28a1a33531af30873ea90c5ac95a9b5/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43013a3f3e2e902e1d05e72c0f1aeb5bedbb8e09240b51e26792a3c89267e181", size = 212401, upload-time = "2026-01-18T20:56:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5d/f70e2c3da414f46186659d24745483757bcc9adccb481a6eb93e2b729301/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7c8b1667a72cbba74f0ae7ecf3105a5e01304620ed14528b2cb4320679d2869b", size = 387082, upload-time = "2026-01-18T20:56:12.047Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d6/06e8dc920c7903e051f30934d874d4afccc9bb1c09dcaf0bc03a7de4b343/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6961442140193e517303d0b5d7bc2e20e69a879c2d774316125350c4a76b92", size = 482346, upload-time = "2026-01-18T20:56:05.152Z" }, + { url = "https://files.pythonhosted.org/packages/66/c4/f337ac0905eed9c393ef990c54565cd33644918e0a8031fe48c098c71dbf/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6a4c34ddef109647c769d69be65fa1de7a6022b02ad45546a69b3216573eb4a", size = 425181, upload-time = "2026-01-18T20:55:37.83Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/6d5758fabef3babdf4bbbc453738cc7de9cd3334e4c38dd5737e27b85653/ormsgpack-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:73670ed0375ecc303858e3613f407628dd1fca18fe6ac57b7b7ce66cc7bb006c", size = 117182, upload-time = "2026-01-18T20:55:31.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/17a15549233c37e7fd054c48fe9207492e06b026dbd872b826a0b5f833b6/ormsgpack-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2be829954434e33601ae5da328cccce3266b098927ca7a30246a0baec2ce7bd", size = 111464, upload-time = "2026-01-18T20:55:38.811Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7a29d09b64b9694b588ff2f80e9826bdceb3a2b91523c5beae1fab27d5c940e7", size = 378618, upload-time = "2026-01-18T20:55:50.835Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/468de634079615abf66ed13bb5c34ff71da237213f29294363beeeca5306/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b39e629fd2e1c5b2f46f99778450b59454d1f901bc507963168985e79f09c5d", size = 203186, upload-time = "2026-01-18T20:56:11.163Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/d756e01961442688b7939bacd87ce13bfad7d26ce24f910f6028178b2cc8/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:958dcb270d30a7cb633a45ee62b9444433fa571a752d2ca484efdac07480876e", size = 210738, upload-time = "2026-01-18T20:56:09.181Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ba/795b1036888542c9113269a3f5690ab53dd2258c6fb17676ac4bd44fcf94/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d379d72b6c5e964851c77cfedfb386e474adee4fd39791c2c5d9efb53505cc", size = 212569, upload-time = "2026-01-18T20:56:06.135Z" }, + { url = "https://files.pythonhosted.org/packages/6c/aa/bff73c57497b9e0cba8837c7e4bcab584b1a6dbc91a5dd5526784a5030c8/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8463a3fc5f09832e67bdb0e2fda6d518dc4281b133166146a67f54c08496442e", size = 387166, upload-time = "2026-01-18T20:55:36.738Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cf/f8283cba44bcb7b14f97b6274d449db276b3a86589bdb363169b51bc12de/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eddffb77eff0bad4e67547d67a130604e7e2dfbb7b0cde0796045be4090f35c6", size = 482498, upload-time = "2026-01-18T20:55:29.626Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/71e37b852d723dfcbe952ad04178c030df60d6b78eba26bfd14c9a40575e/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcd55e5f6ba0dbce624942adf9f152062135f991a0126064889f68eb850de0dd", size = 425518, upload-time = "2026-01-18T20:55:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0c/9803aa883d18c7ef197213cd2cbf73ba76472a11fe100fb7dab2884edf48/ormsgpack-1.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:d024b40828f1dde5654faebd0d824f9cc29ad46891f626272dd5bfd7af2333a4", size = 117462, upload-time = "2026-01-18T20:55:47.726Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9e/029e898298b2cc662f10d7a15652a53e3b525b1e7f07e21fef8536a09bb8/ormsgpack-1.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:da538c542bac7d1c8f3f2a937863dba36f013108ce63e55745941dda4b75dbb6", size = 111559, upload-time = "2026-01-18T20:55:54.273Z" }, + { url = "https://files.pythonhosted.org/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5ea60cb5f210b1cfbad8c002948d73447508e629ec375acb82910e3efa8ff355", size = 378661, upload-time = "2026-01-18T20:55:57.765Z" }, + { url = "https://files.pythonhosted.org/packages/6e/31/5efa31346affdac489acade2926989e019e8ca98129658a183e3add7af5e/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3601f19afdbea273ed70b06495e5794606a8b690a568d6c996a90d7255e51c1", size = 203194, upload-time = "2026-01-18T20:56:08.252Z" }, + { url = "https://files.pythonhosted.org/packages/eb/56/d0087278beef833187e0167f8527235ebe6f6ffc2a143e9de12a98b1ce87/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29a9f17a3dac6054c0dce7925e0f4995c727f7c41859adf9b5572180f640d172", size = 210778, upload-time = "2026-01-18T20:55:17.694Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a2/072343e1413d9443e5a252a8eb591c2d5b1bffbe5e7bfc78c069361b92eb/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39c1bd2092880e413902910388be8715f70b9f15f20779d44e673033a6146f2d", size = 212592, upload-time = "2026-01-18T20:55:32.747Z" }, + { url = "https://files.pythonhosted.org/packages/a2/8b/a0da3b98a91d41187a63b02dda14267eefc2a74fcb43cc2701066cf1510e/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:50b7249244382209877deedeee838aef1542f3d0fc28b8fe71ca9d7e1896a0d7", size = 387164, upload-time = "2026-01-18T20:55:40.853Z" }, + { url = "https://files.pythonhosted.org/packages/19/bb/6d226bc4cf9fc20d8eb1d976d027a3f7c3491e8f08289a2e76abe96a65f3/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:5af04800d844451cf102a59c74a841324868d3f1625c296a06cc655c542a6685", size = 482516, upload-time = "2026-01-18T20:55:42.033Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f1/bb2c7223398543dedb3dbf8bb93aaa737b387de61c5feaad6f908841b782/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cec70477d4371cd524534cd16472d8b9cc187e0e3043a8790545a9a9b296c258", size = 425539, upload-time = "2026-01-18T20:55:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e8/0fb45f57a2ada1fed374f7494c8cd55e2f88ccd0ab0a669aa3468716bf5f/ormsgpack-1.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:21f4276caca5c03a818041d637e4019bc84f9d6ca8baa5ea03e5cc8bf56140e9", size = 117459, upload-time = "2026-01-18T20:55:56.876Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d4/0cfeea1e960d550a131001a7f38a5132c7ae3ebde4c82af1f364ccc5d904/ormsgpack-1.12.2-cp313-cp313-win_arm64.whl", hash = "sha256:baca4b6773d20a82e36d6fd25f341064244f9f86a13dead95dd7d7f996f51709", size = 111577, upload-time = "2026-01-18T20:55:43.605Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pandas" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, + { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281, upload-time = "2025-09-29T23:18:56.834Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453, upload-time = "2025-09-29T23:19:09.247Z" }, + { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361, upload-time = "2025-09-29T23:19:25.342Z" }, + { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702, upload-time = "2025-09-29T23:19:38.296Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, + { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, + { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, + { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, + { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, + { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, + { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, + { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, + { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, + { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, + { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, + { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, + { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, + { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, +] + +[[package]] +name = "partd" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "locket" }, + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/3a/3f06f34820a31257ddcabdfafc2672c5816be79c7e353b02c1f318daa7d4/partd-1.4.2.tar.gz", hash = "sha256:d022c33afbdc8405c226621b015e8067888173d85f7f5ecebb3cafed9a20f02c", size = 21029, upload-time = "2024-05-06T19:51:41.945Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl", hash = "sha256:978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f", size = 18905, upload-time = "2024-05-06T19:51:39.271Z" }, +] + +[[package]] +name = "pillow" +version = "12.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/46/5da1ec4a5171ee7bf1a0efa064aba70ba3d6e0788ce3f5acd1375d23c8c0/pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32", size = 5304084, upload-time = "2026-02-11T04:20:27.501Z" }, + { url = "https://files.pythonhosted.org/packages/78/93/a29e9bc02d1cf557a834da780ceccd54e02421627200696fcf805ebdc3fb/pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38", size = 4657866, upload-time = "2026-02-11T04:20:29.827Z" }, + { url = "https://files.pythonhosted.org/packages/13/84/583a4558d492a179d31e4aae32eadce94b9acf49c0337c4ce0b70e0a01f2/pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5", size = 6232148, upload-time = "2026-02-11T04:20:31.329Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e2/53c43334bbbb2d3b938978532fbda8e62bb6e0b23a26ce8592f36bcc4987/pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090", size = 8038007, upload-time = "2026-02-11T04:20:34.225Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a6/3d0e79c8a9d58150dd98e199d7c1c56861027f3829a3a60b3c2784190180/pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af", size = 6345418, upload-time = "2026-02-11T04:20:35.858Z" }, + { url = "https://files.pythonhosted.org/packages/a2/c8/46dfeac5825e600579157eea177be43e2f7ff4a99da9d0d0a49533509ac5/pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b", size = 7034590, upload-time = "2026-02-11T04:20:37.91Z" }, + { url = "https://files.pythonhosted.org/packages/af/bf/e6f65d3db8a8bbfeaf9e13cc0417813f6319863a73de934f14b2229ada18/pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5", size = 6458655, upload-time = "2026-02-11T04:20:39.496Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c2/66091f3f34a25894ca129362e510b956ef26f8fb67a0e6417bc5744e56f1/pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d", size = 7159286, upload-time = "2026-02-11T04:20:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5a/24bc8eb526a22f957d0cec6243146744966d40857e3d8deb68f7902ca6c1/pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c", size = 6328663, upload-time = "2026-02-11T04:20:43.184Z" }, + { url = "https://files.pythonhosted.org/packages/31/03/bef822e4f2d8f9d7448c133d0a18185d3cce3e70472774fffefe8b0ed562/pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563", size = 7031448, upload-time = "2026-02-11T04:20:44.696Z" }, + { url = "https://files.pythonhosted.org/packages/49/70/f76296f53610bd17b2e7d31728b8b7825e3ac3b5b3688b51f52eab7c0818/pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80", size = 2453651, upload-time = "2026-02-11T04:20:46.243Z" }, + { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" }, + { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" }, + { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" }, + { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" }, + { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" }, + { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" }, + { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" }, + { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" }, + { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" }, + { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" }, + { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" }, + { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" }, + { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" }, + { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" }, + { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" }, + { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" }, + { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" }, + { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" }, + { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" }, + { url = "https://files.pythonhosted.org/packages/56/11/5d43209aa4cb58e0cc80127956ff1796a68b928e6324bbf06ef4db34367b/pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f", size = 5228606, upload-time = "2026-02-11T04:22:52.106Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d5/3b005b4e4fda6698b371fa6c21b097d4707585d7db99e98d9b0b87ac612a/pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9", size = 4622321, upload-time = "2026-02-11T04:22:53.827Z" }, + { url = "https://files.pythonhosted.org/packages/df/36/ed3ea2d594356fd8037e5a01f6156c74bc8d92dbb0fa60746cc96cabb6e8/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e", size = 5247579, upload-time = "2026-02-11T04:22:56.094Z" }, + { url = "https://files.pythonhosted.org/packages/54/9a/9cc3e029683cf6d20ae5085da0dafc63148e3252c2f13328e553aaa13cfb/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9", size = 6989094, upload-time = "2026-02-11T04:22:58.288Z" }, + { url = "https://files.pythonhosted.org/packages/00/98/fc53ab36da80b88df0967896b6c4b4cd948a0dc5aa40a754266aa3ae48b3/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3", size = 5313850, upload-time = "2026-02-11T04:23:00.554Z" }, + { url = "https://files.pythonhosted.org/packages/30/02/00fa585abfd9fe9d73e5f6e554dc36cc2b842898cbfc46d70353dae227f8/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735", size = 5963343, upload-time = "2026-02-11T04:23:02.934Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/c56ce33ca856e358d27fda9676c055395abddb82c35ac0f593877ed4562e/pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e", size = 7029880, upload-time = "2026-02-11T04:23:04.783Z" }, +] + +[[package]] +name = "pip" +version = "26.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747, upload-time = "2026-02-05T02:20:18.702Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723, upload-time = "2026-02-05T02:20:16.416Z" }, +] + +[[package]] +name = "pkce" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/ea/ddd845c2ec21bf1e8555c782b32dc39b82f0b12764feb9f73ccbb2470f13/pkce-1.0.3.tar.gz", hash = "sha256:9775fd76d8a743d39b87df38af1cd04a58c9b5a5242d5a6350ef343d06814ab6", size = 2757, upload-time = "2021-02-08T18:29:07.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/51/52c22ec0812d25f5bf297a01153604bfa7bfa59ed66f6cd8345beb3c2b2a/pkce-1.0.3-py3-none-any.whl", hash = "sha256:55927e24c7d403b2491ebe182b95d9dcb1807643243d47e3879fbda5aad4471d", size = 3200, upload-time = "2021-02-08T18:29:05.678Z" }, +] + +[[package]] +name = "pkginfo" +version = "1.12.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/03/e26bf3d6453b7fda5bd2b84029a426553bb373d6277ef6b5ac8863421f87/pkginfo-1.12.1.2.tar.gz", hash = "sha256:5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b", size = 451828, upload-time = "2025-02-19T15:27:37.188Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/3d/f4f2ba829efb54b6cd2d91349c7463316a9cc55a43fc980447416c88540f/pkginfo-1.12.1.2-py3-none-any.whl", hash = "sha256:c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343", size = 32717, upload-time = "2025-02-19T15:27:33.071Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.9.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" }, +] + +[[package]] +name = "plotly" +version = "6.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "narwhals" }, + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/fb/41efe84970cfddefd4ccf025e2cbfafe780004555f583e93dba3dac2cdef/plotly-6.6.0.tar.gz", hash = "sha256:b897f15f3b02028d69f755f236be890ba950d0a42d7dfc619b44e2d8cea8748c", size = 7027956, upload-time = "2026-03-02T21:10:25.321Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/d2/c6e44dba74f17c6216ce1b56044a9b93a929f1c2d5bdaff892512b260f5e/plotly-6.6.0-py3-none-any.whl", hash = "sha256:8d6daf0f87412e0c0bfe72e809d615217ab57cc715899a1e5145135a7800d1d0", size = 9910315, upload-time = "2026-03-02T21:10:18.131Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "protobuf" +version = "6.33.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, + { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, + { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, + { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, + { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, + { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "pyarrow" +version = "23.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336, upload-time = "2026-02-16T10:14:12.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/41/8e6b6ef7e225d4ceead8459427a52afdc23379768f54dd3566014d7618c1/pyarrow-23.0.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6f0147ee9e0386f519c952cc670eb4a8b05caa594eeffe01af0e25f699e4e9bb", size = 34302230, upload-time = "2026-02-16T10:09:03.859Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4a/1472c00392f521fea03ae93408bf445cc7bfa1ab81683faf9bc188e36629/pyarrow-23.0.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:0ae6e17c828455b6265d590100c295193f93cc5675eb0af59e49dbd00d2de350", size = 35850050, upload-time = "2026-02-16T10:09:11.877Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b2/bd1f2f05ded56af7f54d702c8364c9c43cd6abb91b0e9933f3d77b4f4132/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:fed7020203e9ef273360b9e45be52a2a47d3103caf156a30ace5247ffb51bdbd", size = 44491918, upload-time = "2026-02-16T10:09:18.144Z" }, + { url = "https://files.pythonhosted.org/packages/0b/62/96459ef5b67957eac38a90f541d1c28833d1b367f014a482cb63f3b7cd2d/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:26d50dee49d741ac0e82185033488d28d35be4d763ae6f321f97d1140eb7a0e9", size = 47562811, upload-time = "2026-02-16T10:09:25.792Z" }, + { url = "https://files.pythonhosted.org/packages/7d/94/1170e235add1f5f45a954e26cd0e906e7e74e23392dcb560de471f7366ec/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c30143b17161310f151f4a2bcfe41b5ff744238c1039338779424e38579d701", size = 48183766, upload-time = "2026-02-16T10:09:34.645Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/39a42af4570377b99774cdb47f63ee6c7da7616bd55b3d5001aa18edfe4f/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db2190fa79c80a23fdd29fef4b8992893f024ae7c17d2f5f4db7171fa30c2c78", size = 50607669, upload-time = "2026-02-16T10:09:44.153Z" }, + { url = "https://files.pythonhosted.org/packages/00/ca/db94101c187f3df742133ac837e93b1f269ebdac49427f8310ee40b6a58f/pyarrow-23.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:f00f993a8179e0e1c9713bcc0baf6d6c01326a406a9c23495ec1ba9c9ebf2919", size = 27527698, upload-time = "2026-02-16T10:09:50.263Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4b/4166bb5abbfe6f750fc60ad337c43ecf61340fa52ab386da6e8dbf9e63c4/pyarrow-23.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f4b0dbfa124c0bb161f8b5ebb40f1a680b70279aa0c9901d44a2b5a20806039f", size = 34214575, upload-time = "2026-02-16T10:09:56.225Z" }, + { url = "https://files.pythonhosted.org/packages/e1/da/3f941e3734ac8088ea588b53e860baeddac8323ea40ce22e3d0baa865cc9/pyarrow-23.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:7707d2b6673f7de054e2e83d59f9e805939038eebe1763fe811ee8fa5c0cd1a7", size = 35832540, upload-time = "2026-02-16T10:10:03.428Z" }, + { url = "https://files.pythonhosted.org/packages/88/7c/3d841c366620e906d54430817531b877ba646310296df42ef697308c2705/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:86ff03fb9f1a320266e0de855dee4b17da6794c595d207f89bba40d16b5c78b9", size = 44470940, upload-time = "2026-02-16T10:10:10.704Z" }, + { url = "https://files.pythonhosted.org/packages/2c/a5/da83046273d990f256cb79796a190bbf7ec999269705ddc609403f8c6b06/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:813d99f31275919c383aab17f0f455a04f5a429c261cc411b1e9a8f5e4aaaa05", size = 47586063, upload-time = "2026-02-16T10:10:17.95Z" }, + { url = "https://files.pythonhosted.org/packages/5b/3c/b7d2ebcff47a514f47f9da1e74b7949138c58cfeb108cdd4ee62f43f0cf3/pyarrow-23.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bf5842f960cddd2ef757d486041d57c96483efc295a8c4a0e20e704cbbf39c67", size = 48173045, upload-time = "2026-02-16T10:10:25.363Z" }, + { url = "https://files.pythonhosted.org/packages/43/b2/b40961262213beaba6acfc88698eb773dfce32ecdf34d19291db94c2bd73/pyarrow-23.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564baf97c858ecc03ec01a41062e8f4698abc3e6e2acd79c01c2e97880a19730", size = 50621741, upload-time = "2026-02-16T10:10:33.477Z" }, + { url = "https://files.pythonhosted.org/packages/f6/70/1fdda42d65b28b078e93d75d371b2185a61da89dda4def8ba6ba41ebdeb4/pyarrow-23.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:07deae7783782ac7250989a7b2ecde9b3c343a643f82e8a4df03d93b633006f0", size = 27620678, upload-time = "2026-02-16T10:10:39.31Z" }, + { url = "https://files.pythonhosted.org/packages/47/10/2cbe4c6f0fb83d2de37249567373d64327a5e4d8db72f486db42875b08f6/pyarrow-23.0.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6b8fda694640b00e8af3c824f99f789e836720aa8c9379fb435d4c4953a756b8", size = 34210066, upload-time = "2026-02-16T10:10:45.487Z" }, + { url = "https://files.pythonhosted.org/packages/cb/4f/679fa7e84dadbaca7a65f7cdba8d6c83febbd93ca12fa4adf40ba3b6362b/pyarrow-23.0.1-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:8ff51b1addc469b9444b7c6f3548e19dc931b172ab234e995a60aea9f6e6025f", size = 35825526, upload-time = "2026-02-16T10:10:52.266Z" }, + { url = "https://files.pythonhosted.org/packages/f9/63/d2747d930882c9d661e9398eefc54f15696547b8983aaaf11d4a2e8b5426/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:71c5be5cbf1e1cb6169d2a0980850bccb558ddc9b747b6206435313c47c37677", size = 44473279, upload-time = "2026-02-16T10:11:01.557Z" }, + { url = "https://files.pythonhosted.org/packages/b3/93/10a48b5e238de6d562a411af6467e71e7aedbc9b87f8d3a35f1560ae30fb/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9b6f4f17b43bc39d56fec96e53fe89d94bac3eb134137964371b45352d40d0c2", size = 47585798, upload-time = "2026-02-16T10:11:09.401Z" }, + { url = "https://files.pythonhosted.org/packages/5c/20/476943001c54ef078dbf9542280e22741219a184a0632862bca4feccd666/pyarrow-23.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fc13fc6c403d1337acab46a2c4346ca6c9dec5780c3c697cf8abfd5e19b6b37", size = 48179446, upload-time = "2026-02-16T10:11:17.781Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b6/5dd0c47b335fcd8edba9bfab78ad961bd0fd55ebe53468cc393f45e0be60/pyarrow-23.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c16ed4f53247fa3ffb12a14d236de4213a4415d127fe9cebed33d51671113e2", size = 50623972, upload-time = "2026-02-16T10:11:26.185Z" }, + { url = "https://files.pythonhosted.org/packages/d5/09/a532297c9591a727d67760e2e756b83905dd89adb365a7f6e9c72578bcc1/pyarrow-23.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:cecfb12ef629cf6be0b1887f9f86463b0dd3dc3195ae6224e74006be4736035a", size = 27540749, upload-time = "2026-02-16T10:12:23.297Z" }, + { url = "https://files.pythonhosted.org/packages/a5/8e/38749c4b1303e6ae76b3c80618f84861ae0c55dd3c2273842ea6f8258233/pyarrow-23.0.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:29f7f7419a0e30264ea261fdc0e5fe63ce5a6095003db2945d7cd78df391a7e1", size = 34471544, upload-time = "2026-02-16T10:11:32.535Z" }, + { url = "https://files.pythonhosted.org/packages/a3/73/f237b2bc8c669212f842bcfd842b04fc8d936bfc9d471630569132dc920d/pyarrow-23.0.1-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:33d648dc25b51fd8055c19e4261e813dfc4d2427f068bcecc8b53d01b81b0500", size = 35949911, upload-time = "2026-02-16T10:11:39.813Z" }, + { url = "https://files.pythonhosted.org/packages/0c/86/b912195eee0903b5611bf596833def7d146ab2d301afeb4b722c57ffc966/pyarrow-23.0.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd395abf8f91c673dd3589cadc8cc1ee4e8674fa61b2e923c8dd215d9c7d1f41", size = 44520337, upload-time = "2026-02-16T10:11:47.764Z" }, + { url = "https://files.pythonhosted.org/packages/69/c2/f2a717fb824f62d0be952ea724b4f6f9372a17eed6f704b5c9526f12f2f1/pyarrow-23.0.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:00be9576d970c31defb5c32eb72ef585bf600ef6d0a82d5eccaae96639cf9d07", size = 47548944, upload-time = "2026-02-16T10:11:56.607Z" }, + { url = "https://files.pythonhosted.org/packages/84/a7/90007d476b9f0dc308e3bc57b832d004f848fd6c0da601375d20d92d1519/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c2139549494445609f35a5cda4eb94e2c9e4d704ce60a095b342f82460c73a83", size = 48236269, upload-time = "2026-02-16T10:12:04.47Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3f/b16fab3e77709856eb6ac328ce35f57a6d4a18462c7ca5186ef31b45e0e0/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7044b442f184d84e2351e5084600f0d7343d6117aabcbc1ac78eb1ae11eb4125", size = 50604794, upload-time = "2026-02-16T10:12:11.797Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a1/22df0620a9fac31d68397a75465c344e83c3dfe521f7612aea33e27ab6c0/pyarrow-23.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a35581e856a2fafa12f3f54fce4331862b1cfb0bef5758347a858a4aa9d6bae8", size = 27660642, upload-time = "2026-02-16T10:12:17.746Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" }, +] + +[[package]] +name = "pymilvus" +version = "2.6.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "grpcio" }, + { name = "orjson" }, + { name = "pandas" }, + { name = "protobuf" }, + { name = "python-dotenv" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/0c/92adff800a04cd3e9b3f17c06fa972c8d590846b1e0bac0ccf39e054b596/pymilvus-2.6.9.tar.gz", hash = "sha256:c53a3d84ff15814e251be13edda70a98a1c8a6090d7597a908387cbb94a9504a", size = 1493560, upload-time = "2026-02-10T11:01:27.415Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/56/ab7f0a5aba6fc06dc210a059d6f6d2ee1f3371d40e2b4366a409576554b8/pymilvus-2.6.9-py3-none-any.whl", hash = "sha256:3e14e8072f6429dcd79d52a24dc021c594cb80841ddd76cb974bc539d1f4cdda", size = 301225, upload-time = "2026-02-10T11:01:25.796Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855, upload-time = "2024-08-22T08:03:18.145Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024, upload-time = "2024-08-22T08:03:15.536Z" }, +] + +[[package]] +name = "pytest-cov" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/4c/f883ab8f0daad69f47efdf95f55a66b51a8b939c430dadce0611508d9e99/pytest_cov-6.3.0.tar.gz", hash = "sha256:35c580e7800f87ce892e687461166e1ac2bcb8fb9e13aea79032518d6e503ff2", size = 70398, upload-time = "2025-09-06T15:40:14.361Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/b4/bb7263e12aade3842b938bc5c6958cae79c5ee18992f9b9349019579da0f/pytest_cov-6.3.0-py3-none-any.whl", hash = "sha256:440db28156d2468cafc0415b4f8e50856a0d11faefa38f30906048fe490f1749", size = 25115, upload-time = "2025-09-06T15:40:12.44Z" }, +] + +[[package]] +name = "pytest-httpserver" +version = "1.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/17/ad187f46998814014f7cda309de700b87c0eb4b2e111e18bc8c819be7116/pytest_httpserver-1.1.5.tar.gz", hash = "sha256:dc3d82e1fe00e491829d8939c549bf4bd9b39a260f87113c619b9d517c2f8ff1", size = 70974, upload-time = "2026-02-14T13:27:23.412Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/df/0bdf90b84c6a586a9fd2b509523a3ab26b1cc1b1dba2fb62a32e4411ea9e/pytest_httpserver-1.1.5-py3-none-any.whl", hash = "sha256:ee83feb587ab652c0c6729598db2820e9048233bac8df756818b7845a1621d0a", size = 23330, upload-time = "2026-02-14T13:27:22.119Z" }, +] + +[[package]] +name = "pytest-timeout" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +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-multipart" +version = "0.0.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, +] + +[[package]] +name = "pytz" +version = "2026.1.post1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +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.2.28" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/71/41455aa99a5a5ac1eaf311f5d8efd9ce6433c03ac1e0962de163350d0d97/regex-2026.2.28.tar.gz", hash = "sha256:a729e47d418ea11d03469f321aaf67cdee8954cde3ff2cf8403ab87951ad10f2", size = 415184, upload-time = "2026-02-28T02:19:42.792Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/db/8cbfd0ba3f302f2d09dd0019a9fcab74b63fee77a76c937d0e33161fb8c1/regex-2026.2.28-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e621fb7c8dc147419b28e1702f58a0177ff8308a76fa295c71f3e7827849f5d9", size = 488462, upload-time = "2026-02-28T02:16:22.616Z" }, + { url = "https://files.pythonhosted.org/packages/5d/10/ccc22c52802223f2368731964ddd117799e1390ffc39dbb31634a83022ee/regex-2026.2.28-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d5bef2031cbf38757a0b0bc4298bb4824b6332d28edc16b39247228fbdbad97", size = 290774, upload-time = "2026-02-28T02:16:23.993Z" }, + { url = "https://files.pythonhosted.org/packages/62/b9/6796b3bf3101e64117201aaa3a5a030ec677ecf34b3cd6141b5d5c6c67d5/regex-2026.2.28-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bcb399ed84eabf4282587ba151f2732ad8168e66f1d3f85b1d038868fe547703", size = 288724, upload-time = "2026-02-28T02:16:25.403Z" }, + { url = "https://files.pythonhosted.org/packages/9c/02/291c0ae3f3a10cea941d0f5366da1843d8d1fa8a25b0671e20a0e454bb38/regex-2026.2.28-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c1b34dfa72f826f535b20712afa9bb3ba580020e834f3c69866c5bddbf10098", size = 791924, upload-time = "2026-02-28T02:16:26.863Z" }, + { url = "https://files.pythonhosted.org/packages/0f/57/f0235cc520d9672742196c5c15098f8f703f2758d48d5a7465a56333e496/regex-2026.2.28-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:851fa70df44325e1e4cdb79c5e676e91a78147b1b543db2aec8734d2add30ec2", size = 860095, upload-time = "2026-02-28T02:16:28.772Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7c/393c94cbedda79a0f5f2435ebd01644aba0b338d327eb24b4aa5b8d6c07f/regex-2026.2.28-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:516604edd17b1c2c3e579cf4e9b25a53bf8fa6e7cedddf1127804d3e0140ca64", size = 906583, upload-time = "2026-02-28T02:16:30.977Z" }, + { url = "https://files.pythonhosted.org/packages/2c/73/a72820f47ca5abf2b5d911d0407ba5178fc52cf9780191ed3a54f5f419a2/regex-2026.2.28-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7ce83654d1ab701cb619285a18a8e5a889c1216d746ddc710c914ca5fd71022", size = 800234, upload-time = "2026-02-28T02:16:32.55Z" }, + { url = "https://files.pythonhosted.org/packages/34/b3/6e6a4b7b31fa998c4cf159a12cbeaf356386fbd1a8be743b1e80a3da51e4/regex-2026.2.28-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2791948f7c70bb9335a9102df45e93d428f4b8128020d85920223925d73b9e1", size = 772803, upload-time = "2026-02-28T02:16:34.029Z" }, + { url = "https://files.pythonhosted.org/packages/10/e7/5da0280c765d5a92af5e1cd324b3fe8464303189cbaa449de9a71910e273/regex-2026.2.28-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03a83cc26aa2acda6b8b9dfe748cf9e84cbd390c424a1de34fdcef58961a297a", size = 781117, upload-time = "2026-02-28T02:16:36.253Z" }, + { url = "https://files.pythonhosted.org/packages/76/39/0b8d7efb256ae34e1b8157acc1afd8758048a1cf0196e1aec2e71fd99f4b/regex-2026.2.28-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ec6f5674c5dc836994f50f1186dd1fafde4be0666aae201ae2fcc3d29d8adf27", size = 854224, upload-time = "2026-02-28T02:16:38.119Z" }, + { url = "https://files.pythonhosted.org/packages/21/ff/a96d483ebe8fe6d1c67907729202313895d8de8495569ec319c6f29d0438/regex-2026.2.28-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:50c2fc924749543e0eacc93ada6aeeb3ea5f6715825624baa0dccaec771668ae", size = 761898, upload-time = "2026-02-28T02:16:40.333Z" }, + { url = "https://files.pythonhosted.org/packages/89/bd/d4f2e75cb4a54b484e796017e37c0d09d8a0a837de43d17e238adf163f4e/regex-2026.2.28-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ba55c50f408fb5c346a3a02d2ce0ebc839784e24f7c9684fde328ff063c3cdea", size = 844832, upload-time = "2026-02-28T02:16:41.875Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a7/428a135cf5e15e4e11d1e696eb2bf968362f8ea8a5f237122e96bc2ae950/regex-2026.2.28-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:edb1b1b3a5576c56f08ac46f108c40333f222ebfd5cf63afdfa3aab0791ebe5b", size = 788347, upload-time = "2026-02-28T02:16:43.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/59/68691428851cf9c9c3707217ab1d9b47cfeec9d153a49919e6c368b9e926/regex-2026.2.28-cp311-cp311-win32.whl", hash = "sha256:948c12ef30ecedb128903c2c2678b339746eb7c689c5c21957c4a23950c96d15", size = 266033, upload-time = "2026-02-28T02:16:45.094Z" }, + { url = "https://files.pythonhosted.org/packages/42/8b/1483de1c57024e89296cbcceb9cccb3f625d416ddb46e570be185c9b05a9/regex-2026.2.28-cp311-cp311-win_amd64.whl", hash = "sha256:fd63453f10d29097cc3dc62d070746523973fb5aa1c66d25f8558bebd47fed61", size = 277978, upload-time = "2026-02-28T02:16:46.75Z" }, + { url = "https://files.pythonhosted.org/packages/a4/36/abec45dc6e7252e3dbc797120496e43bb5730a7abf0d9cb69340696a2f2d/regex-2026.2.28-cp311-cp311-win_arm64.whl", hash = "sha256:00f2b8d9615aa165fdff0a13f1a92049bfad555ee91e20d246a51aa0b556c60a", size = 270340, upload-time = "2026-02-28T02:16:48.626Z" }, + { url = "https://files.pythonhosted.org/packages/07/42/9061b03cf0fc4b5fa2c3984cbbaed54324377e440a5c5a29d29a72518d62/regex-2026.2.28-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fcf26c3c6d0da98fada8ae4ef0aa1c3405a431c0a77eb17306d38a89b02adcd7", size = 489574, upload-time = "2026-02-28T02:16:50.455Z" }, + { url = "https://files.pythonhosted.org/packages/77/83/0c8a5623a233015595e3da499c5a1c13720ac63c107897a6037bb97af248/regex-2026.2.28-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02473c954af35dd2defeb07e44182f5705b30ea3f351a7cbffa9177beb14da5d", size = 291426, upload-time = "2026-02-28T02:16:52.52Z" }, + { url = "https://files.pythonhosted.org/packages/9e/06/3ef1ac6910dc3295ebd71b1f9bfa737e82cfead211a18b319d45f85ddd09/regex-2026.2.28-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9b65d33a17101569f86d9c5966a8b1d7fbf8afdda5a8aa219301b0a80f58cf7d", size = 289200, upload-time = "2026-02-28T02:16:54.08Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c9/8cc8d850b35ab5650ff6756a1cb85286e2000b66c97520b29c1587455344/regex-2026.2.28-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e71dcecaa113eebcc96622c17692672c2d104b1d71ddf7adeda90da7ddeb26fc", size = 796765, upload-time = "2026-02-28T02:16:55.905Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5d/57702597627fc23278ebf36fbb497ac91c0ce7fec89ac6c81e420ca3e38c/regex-2026.2.28-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:481df4623fa4969c8b11f3433ed7d5e3dc9cec0f008356c3212b3933fb77e3d8", size = 863093, upload-time = "2026-02-28T02:16:58.094Z" }, + { url = "https://files.pythonhosted.org/packages/02/6d/f3ecad537ca2811b4d26b54ca848cf70e04fcfc138667c146a9f3157779c/regex-2026.2.28-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:64e7c6ad614573e0640f271e811a408d79a9e1fe62a46adb602f598df42a818d", size = 909455, upload-time = "2026-02-28T02:17:00.918Z" }, + { url = "https://files.pythonhosted.org/packages/9e/40/bb226f203caa22c1043c1ca79b36340156eca0f6a6742b46c3bb222a3a57/regex-2026.2.28-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6b08a06976ff4fb0d83077022fde3eca06c55432bb997d8c0495b9a4e9872f4", size = 802037, upload-time = "2026-02-28T02:17:02.842Z" }, + { url = "https://files.pythonhosted.org/packages/44/7c/c6d91d8911ac6803b45ca968e8e500c46934e58c0903cbc6d760ee817a0a/regex-2026.2.28-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:864cdd1a2ef5716b0ab468af40139e62ede1b3a53386b375ec0786bb6783fc05", size = 775113, upload-time = "2026-02-28T02:17:04.506Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8d/4a9368d168d47abd4158580b8c848709667b1cd293ff0c0c277279543bd0/regex-2026.2.28-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:511f7419f7afab475fd4d639d4aedfc54205bcb0800066753ef68a59f0f330b5", size = 784194, upload-time = "2026-02-28T02:17:06.888Z" }, + { url = "https://files.pythonhosted.org/packages/cc/bf/2c72ab5d8b7be462cb1651b5cc333da1d0068740342f350fcca3bca31947/regex-2026.2.28-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b42f7466e32bf15a961cf09f35fa6323cc72e64d3d2c990b10de1274a5da0a59", size = 856846, upload-time = "2026-02-28T02:17:09.11Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f4/6b65c979bb6d09f51bb2d2a7bc85de73c01ec73335d7ddd202dcb8cd1c8f/regex-2026.2.28-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8710d61737b0c0ce6836b1da7109f20d495e49b3809f30e27e9560be67a257bf", size = 763516, upload-time = "2026-02-28T02:17:11.004Z" }, + { url = "https://files.pythonhosted.org/packages/8e/32/29ea5e27400ee86d2cc2b4e80aa059df04eaf78b4f0c18576ae077aeff68/regex-2026.2.28-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4390c365fd2d45278f45afd4673cb90f7285f5701607e3ad4274df08e36140ae", size = 849278, upload-time = "2026-02-28T02:17:12.693Z" }, + { url = "https://files.pythonhosted.org/packages/1d/91/3233d03b5f865111cd517e1c95ee8b43e8b428d61fa73764a80c9bb6f537/regex-2026.2.28-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cb3b1db8ff6c7b8bf838ab05583ea15230cb2f678e569ab0e3a24d1e8320940b", size = 790068, upload-time = "2026-02-28T02:17:14.9Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/abc706c1fb03b4580a09645b206a3fc032f5a9f457bc1a8038ac555658ab/regex-2026.2.28-cp312-cp312-win32.whl", hash = "sha256:f8ed9a5d4612df9d4de15878f0bc6aa7a268afbe5af21a3fdd97fa19516e978c", size = 266416, upload-time = "2026-02-28T02:17:17.15Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/2a6f7dff190e5fa9df9fb4acf2fdf17a1aa0f7f54596cba8de608db56b3a/regex-2026.2.28-cp312-cp312-win_amd64.whl", hash = "sha256:01d65fd24206c8e1e97e2e31b286c59009636c022eb5d003f52760b0f42155d4", size = 277297, upload-time = "2026-02-28T02:17:18.723Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f0/58a2484851fadf284458fdbd728f580d55c1abac059ae9f048c63b92f427/regex-2026.2.28-cp312-cp312-win_arm64.whl", hash = "sha256:c0b5ccbb8ffb433939d248707d4a8b31993cb76ab1a0187ca886bf50e96df952", size = 270408, upload-time = "2026-02-28T02:17:20.328Z" }, + { url = "https://files.pythonhosted.org/packages/87/f6/dc9ef48c61b79c8201585bf37fa70cd781977da86e466cd94e8e95d2443b/regex-2026.2.28-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6d63a07e5ec8ce7184452cb00c41c37b49e67dc4f73b2955b5b8e782ea970784", size = 489311, upload-time = "2026-02-28T02:17:22.591Z" }, + { url = "https://files.pythonhosted.org/packages/95/c8/c20390f2232d3f7956f420f4ef1852608ad57aa26c3dd78516cb9f3dc913/regex-2026.2.28-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e59bc8f30414d283ae8ee1617b13d8112e7135cb92830f0ec3688cb29152585a", size = 291285, upload-time = "2026-02-28T02:17:24.355Z" }, + { url = "https://files.pythonhosted.org/packages/d2/a6/ba1068a631ebd71a230e7d8013fcd284b7c89c35f46f34a7da02082141b1/regex-2026.2.28-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:de0cf053139f96219ccfabb4a8dd2d217c8c82cb206c91d9f109f3f552d6b43d", size = 289051, upload-time = "2026-02-28T02:17:26.722Z" }, + { url = "https://files.pythonhosted.org/packages/1d/1b/7cc3b7af4c244c204b7a80924bd3d85aecd9ba5bc82b485c5806ee8cda9e/regex-2026.2.28-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb4db2f17e6484904f986c5a657cec85574c76b5c5e61c7aae9ffa1bc6224f95", size = 796842, upload-time = "2026-02-28T02:17:29.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/87/26bd03efc60e0d772ac1e7b60a2e6325af98d974e2358f659c507d3c76db/regex-2026.2.28-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52b017b35ac2214d0db5f4f90e303634dc44e4aba4bd6235a27f97ecbe5b0472", size = 863083, upload-time = "2026-02-28T02:17:31.363Z" }, + { url = "https://files.pythonhosted.org/packages/ae/54/aeaf4afb1aa0a65e40de52a61dc2ac5b00a83c6cb081c8a1d0dda74f3010/regex-2026.2.28-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:69fc560ccbf08a09dc9b52ab69cacfae51e0ed80dc5693078bdc97db2f91ae96", size = 909412, upload-time = "2026-02-28T02:17:33.248Z" }, + { url = "https://files.pythonhosted.org/packages/12/2f/049901def913954e640d199bbc6a7ca2902b6aeda0e5da9d17f114100ec2/regex-2026.2.28-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e61eea47230eba62a31f3e8a0e3164d0f37ef9f40529fb2c79361bc6b53d2a92", size = 802101, upload-time = "2026-02-28T02:17:35.053Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/512fb9ff7f5b15ea204bb1967ebb649059446decacccb201381f9fa6aad4/regex-2026.2.28-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4f5c0b182ad4269e7381b7c27fdb0408399881f7a92a4624fd5487f2971dfc11", size = 775260, upload-time = "2026-02-28T02:17:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/9a92935878aba19bd72706b9db5646a6f993d99b3f6ed42c02ec8beb1d61/regex-2026.2.28-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:96f6269a2882fbb0ee76967116b83679dc628e68eaea44e90884b8d53d833881", size = 784311, upload-time = "2026-02-28T02:17:39.855Z" }, + { url = "https://files.pythonhosted.org/packages/09/d3/fc51a8a738a49a6b6499626580554c9466d3ea561f2b72cfdc72e4149773/regex-2026.2.28-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b5acd4b6a95f37c3c3828e5d053a7d4edaedb85de551db0153754924cb7c83e3", size = 856876, upload-time = "2026-02-28T02:17:42.317Z" }, + { url = "https://files.pythonhosted.org/packages/08/b7/2e641f3d084b120ca4c52e8c762a78da0b32bf03ef546330db3e2635dc5f/regex-2026.2.28-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2234059cfe33d9813a3677ef7667999caea9eeaa83fef98eb6ce15c6cf9e0215", size = 763632, upload-time = "2026-02-28T02:17:45.073Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6d/0009021d97e79ee99f3d8641f0a8d001eed23479ade4c3125a5480bf3e2d/regex-2026.2.28-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c15af43c72a7fb0c97cbc66fa36a43546eddc5c06a662b64a0cbf30d6ac40944", size = 849320, upload-time = "2026-02-28T02:17:47.192Z" }, + { url = "https://files.pythonhosted.org/packages/05/7a/51cfbad5758f8edae430cb21961a9c8d04bce1dae4d2d18d4186eec7cfa1/regex-2026.2.28-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9185cc63359862a6e80fe97f696e04b0ad9a11c4ac0a4a927f979f611bfe3768", size = 790152, upload-time = "2026-02-28T02:17:49.067Z" }, + { url = "https://files.pythonhosted.org/packages/90/3d/a83e2b6b3daa142acb8c41d51de3876186307d5cb7490087031747662500/regex-2026.2.28-cp313-cp313-win32.whl", hash = "sha256:fb66e5245db9652abd7196ace599b04d9c0e4aa7c8f0e2803938377835780081", size = 266398, upload-time = "2026-02-28T02:17:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/16e9ebb1fe5425e11b9596c8d57bf8877dcb32391da0bfd33742e3290637/regex-2026.2.28-cp313-cp313-win_amd64.whl", hash = "sha256:71a911098be38c859ceb3f9a9ce43f4ed9f4c6720ad8684a066ea246b76ad9ff", size = 277282, upload-time = "2026-02-28T02:17:53.074Z" }, + { url = "https://files.pythonhosted.org/packages/07/b4/92851335332810c5a89723bf7a7e35c7209f90b7d4160024501717b28cc9/regex-2026.2.28-cp313-cp313-win_arm64.whl", hash = "sha256:39bb5727650b9a0275c6a6690f9bb3fe693a7e6cc5c3155b1240aedf8926423e", size = 270382, upload-time = "2026-02-28T02:17:54.888Z" }, + { url = "https://files.pythonhosted.org/packages/24/07/6c7e4cec1e585959e96cbc24299d97e4437a81173217af54f1804994e911/regex-2026.2.28-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:97054c55db06ab020342cc0d35d6f62a465fa7662871190175f1ad6c655c028f", size = 492541, upload-time = "2026-02-28T02:17:56.813Z" }, + { url = "https://files.pythonhosted.org/packages/7c/13/55eb22ada7f43d4f4bb3815b6132183ebc331c81bd496e2d1f3b8d862e0d/regex-2026.2.28-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d25a10811de831c2baa6aef3c0be91622f44dd8d31dd12e69f6398efb15e48b", size = 292984, upload-time = "2026-02-28T02:17:58.538Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/c301f8cb29ce9644a5ef85104c59244e6e7e90994a0f458da4d39baa8e17/regex-2026.2.28-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d6cfe798d8da41bb1862ed6e0cba14003d387c3c0c4a5d45591076ae9f0ce2f8", size = 291509, upload-time = "2026-02-28T02:18:00.208Z" }, + { url = "https://files.pythonhosted.org/packages/b5/43/aabe384ec1994b91796e903582427bc2ffaed9c4103819ed3c16d8e749f3/regex-2026.2.28-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd0ce43e71d825b7c0661f9c54d4d74bd97c56c3fd102a8985bcfea48236bacb", size = 809429, upload-time = "2026-02-28T02:18:02.328Z" }, + { url = "https://files.pythonhosted.org/packages/04/b8/8d2d987a816720c4f3109cee7c06a4b24ad0e02d4fc74919ab619e543737/regex-2026.2.28-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00945d007fd74a9084d2ab79b695b595c6b7ba3698972fadd43e23230c6979c1", size = 869422, upload-time = "2026-02-28T02:18:04.23Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ad/2c004509e763c0c3719f97c03eca26473bffb3868d54c5f280b8cd4f9e3d/regex-2026.2.28-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bec23c11cbbf09a4df32fe50d57cbdd777bc442269b6e39a1775654f1c95dee2", size = 915175, upload-time = "2026-02-28T02:18:06.791Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/fd429066da487ef555a9da73bf214894aec77fc8c66a261ee355a69871a8/regex-2026.2.28-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5cdcc17d935c8f9d3f4db5c2ebe2640c332e3822ad5d23c2f8e0228e6947943a", size = 812044, upload-time = "2026-02-28T02:18:08.736Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ca/feedb7055c62a3f7f659971bf45f0e0a87544b6b0cf462884761453f97c5/regex-2026.2.28-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a448af01e3d8031c89c5d902040b124a5e921a25c4e5e07a861ca591ce429341", size = 782056, upload-time = "2026-02-28T02:18:10.777Z" }, + { url = "https://files.pythonhosted.org/packages/95/30/1aa959ed0d25c1dd7dd5047ea8ba482ceaef38ce363c401fd32a6b923e60/regex-2026.2.28-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:10d28e19bd4888e4abf43bd3925f3c134c52fdf7259219003588a42e24c2aa25", size = 798743, upload-time = "2026-02-28T02:18:13.025Z" }, + { url = "https://files.pythonhosted.org/packages/3b/1f/dadb9cf359004784051c897dcf4d5d79895f73a1bbb7b827abaa4814ae80/regex-2026.2.28-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:99985a2c277dcb9ccb63f937451af5d65177af1efdeb8173ac55b61095a0a05c", size = 864633, upload-time = "2026-02-28T02:18:16.84Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f1/b9a25eb24e1cf79890f09e6ec971ee5b511519f1851de3453bc04f6c902b/regex-2026.2.28-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:e1e7b24cb3ae9953a560c563045d1ba56ee4749fbd05cf21ba571069bd7be81b", size = 770862, upload-time = "2026-02-28T02:18:18.892Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/c5cb10b7aa6f182f9247a30cc9527e326601f46f4df864ac6db588d11fcd/regex-2026.2.28-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d8511a01d0e4ee1992eb3ba19e09bc1866fe03f05129c3aec3fdc4cbc77aad3f", size = 854788, upload-time = "2026-02-28T02:18:21.475Z" }, + { url = "https://files.pythonhosted.org/packages/0a/50/414ba0731c4bd40b011fa4703b2cc86879ec060c64f2a906e65a56452589/regex-2026.2.28-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:aaffaecffcd2479ce87aa1e74076c221700b7c804e48e98e62500ee748f0f550", size = 800184, upload-time = "2026-02-28T02:18:23.492Z" }, + { url = "https://files.pythonhosted.org/packages/69/50/0c7290987f97e7e6830b0d853f69dc4dc5852c934aae63e7fdcd76b4c383/regex-2026.2.28-cp313-cp313t-win32.whl", hash = "sha256:ef77bdde9c9eba3f7fa5b58084b29bbcc74bcf55fdbeaa67c102a35b5bd7e7cc", size = 269137, upload-time = "2026-02-28T02:18:25.375Z" }, + { url = "https://files.pythonhosted.org/packages/68/80/ef26ff90e74ceb4051ad6efcbbb8a4be965184a57e879ebcbdef327d18fa/regex-2026.2.28-cp313-cp313t-win_amd64.whl", hash = "sha256:98adf340100cbe6fbaf8e6dc75e28f2c191b1be50ffefe292fb0e6f6eefdb0d8", size = 280682, upload-time = "2026-02-28T02:18:27.205Z" }, + { url = "https://files.pythonhosted.org/packages/69/8b/fbad9c52e83ffe8f97e3ed1aa0516e6dff6bb633a41da9e64645bc7efdc5/regex-2026.2.28-cp313-cp313t-win_arm64.whl", hash = "sha256:2fb950ac1d88e6b6a9414381f403797b236f9fa17e1eee07683af72b1634207b", size = 271735, upload-time = "2026-02-28T02:18:29.015Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +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 = "14.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, + { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, + { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, + { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, + { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, + { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, + { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, + { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, + { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, + { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, + { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" }, + { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" }, + { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" }, + { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" }, + { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" }, + { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" }, + { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, + { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, + { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, + { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, + { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, + { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, + { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, + { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, + { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, + { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, + { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, + { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, + { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, + { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, + { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, + { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, +] + +[[package]] +name = "s3transfer" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/74/8d69dcb7a9efe8baa2046891735e5dfe433ad558ae23d9e3c14c633d1d58/s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125", size = 151547, upload-time = "2025-09-09T19:23:31.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f0/ae7ca09223a81a1d890b2557186ea015f6e0502e9b8cb8e1813f1d8cfa4e/s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456", size = 85712, upload-time = "2025-09-09T19:23:30.041Z" }, +] + +[[package]] +name = "safetensors" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, +] + +[[package]] +name = "setuptools" +version = "82.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893, upload-time = "2026-02-08T15:08:40.206Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468, upload-time = "2026-02-08T15:08:38.723Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.48" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/73/b4a9737255583b5fa858e0bb8e116eb94b88c910164ed2ed719147bde3de/sqlalchemy-2.0.48.tar.gz", hash = "sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7", size = 9886075, upload-time = "2026-03-02T15:28:51.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/6d/b8b78b5b80f3c3ab3f7fa90faa195ec3401f6d884b60221260fd4d51864c/sqlalchemy-2.0.48-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b4c575df7368b3b13e0cebf01d4679f9a28ed2ae6c1cd0b1d5beffb6b2007dc", size = 2157184, upload-time = "2026-03-02T15:38:28.161Z" }, + { url = "https://files.pythonhosted.org/packages/21/4b/4f3d4a43743ab58b95b9ddf5580a265b593d017693df9e08bd55780af5bb/sqlalchemy-2.0.48-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e83e3f959aaa1c9df95c22c528096d94848a1bc819f5d0ebf7ee3df0ca63db6c", size = 3313555, upload-time = "2026-03-02T15:58:57.21Z" }, + { url = "https://files.pythonhosted.org/packages/21/dd/3b7c53f1dbbf736fd27041aee68f8ac52226b610f914085b1652c2323442/sqlalchemy-2.0.48-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f7b7243850edd0b8b97043f04748f31de50cf426e939def5c16bedb540698f7", size = 3313057, upload-time = "2026-03-02T15:52:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/cc/3e600a90ae64047f33313d7d32e5ad025417f09d2ded487e8284b5e21a15/sqlalchemy-2.0.48-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:82745b03b4043e04600a6b665cb98697c4339b24e34d74b0a2ac0a2488b6f94d", size = 3265431, upload-time = "2026-03-02T15:58:59.096Z" }, + { url = "https://files.pythonhosted.org/packages/8b/19/780138dacfe3f5024f4cf96e4005e91edf6653d53d3673be4844578faf1d/sqlalchemy-2.0.48-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e5e088bf43f6ee6fec7dbf1ef7ff7774a616c236b5c0cb3e00662dd71a56b571", size = 3287646, upload-time = "2026-03-02T15:52:31.569Z" }, + { url = "https://files.pythonhosted.org/packages/40/fd/f32ced124f01a23151f4777e4c705f3a470adc7bd241d9f36a7c941a33bf/sqlalchemy-2.0.48-cp311-cp311-win32.whl", hash = "sha256:9c7d0a77e36b5f4b01ca398482230ab792061d243d715299b44a0b55c89fe617", size = 2116956, upload-time = "2026-03-02T15:46:54.535Z" }, + { url = "https://files.pythonhosted.org/packages/58/d5/dd767277f6feef12d05651538f280277e661698f617fa4d086cce6055416/sqlalchemy-2.0.48-cp311-cp311-win_amd64.whl", hash = "sha256:583849c743e0e3c9bb7446f5b5addeacedc168d657a69b418063dfdb2d90081c", size = 2141627, upload-time = "2026-03-02T15:46:55.849Z" }, + { url = "https://files.pythonhosted.org/packages/ef/91/a42ae716f8925e9659df2da21ba941f158686856107a61cc97a95e7647a3/sqlalchemy-2.0.48-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:348174f228b99f33ca1f773e85510e08927620caa59ffe7803b37170df30332b", size = 2155737, upload-time = "2026-03-02T15:49:13.207Z" }, + { url = "https://files.pythonhosted.org/packages/b9/52/f75f516a1f3888f027c1cfb5d22d4376f4b46236f2e8669dcb0cddc60275/sqlalchemy-2.0.48-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53667b5f668991e279d21f94ccfa6e45b4e3f4500e7591ae59a8012d0f010dcb", size = 3337020, upload-time = "2026-03-02T15:50:34.547Z" }, + { url = "https://files.pythonhosted.org/packages/37/9a/0c28b6371e0cdcb14f8f1930778cb3123acfcbd2c95bb9cf6b4a2ba0cce3/sqlalchemy-2.0.48-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34634e196f620c7a61d18d5cf7dc841ca6daa7961aed75d532b7e58b309ac894", size = 3349983, upload-time = "2026-03-02T15:53:25.542Z" }, + { url = "https://files.pythonhosted.org/packages/1c/46/0aee8f3ff20b1dcbceb46ca2d87fcc3d48b407925a383ff668218509d132/sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:546572a1793cc35857a2ffa1fe0e58571af1779bcc1ffa7c9fb0839885ed69a9", size = 3279690, upload-time = "2026-03-02T15:50:36.277Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8c/a957bc91293b49181350bfd55e6dfc6e30b7f7d83dc6792d72043274a390/sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:07edba08061bc277bfdc772dd2a1a43978f5a45994dd3ede26391b405c15221e", size = 3314738, upload-time = "2026-03-02T15:53:27.519Z" }, + { url = "https://files.pythonhosted.org/packages/4b/44/1d257d9f9556661e7bdc83667cc414ba210acfc110c82938cb3611eea58f/sqlalchemy-2.0.48-cp312-cp312-win32.whl", hash = "sha256:908a3fa6908716f803b86896a09a2c4dde5f5ce2bb07aacc71ffebb57986ce99", size = 2115546, upload-time = "2026-03-02T15:54:31.591Z" }, + { url = "https://files.pythonhosted.org/packages/f2/af/c3c7e1f3a2b383155a16454df62ae8c62a30dd238e42e68c24cebebbfae6/sqlalchemy-2.0.48-cp312-cp312-win_amd64.whl", hash = "sha256:68549c403f79a8e25984376480959975212a670405e3913830614432b5daa07a", size = 2142484, upload-time = "2026-03-02T15:54:34.072Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c6/569dc8bf3cd375abc5907e82235923e986799f301cd79a903f784b996fca/sqlalchemy-2.0.48-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e3070c03701037aa418b55d36532ecb8f8446ed0135acb71c678dbdf12f5b6e4", size = 2152599, upload-time = "2026-03-02T15:49:14.41Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ff/f4e04a4bd5a24304f38cb0d4aa2ad4c0fb34999f8b884c656535e1b2b74c/sqlalchemy-2.0.48-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2645b7d8a738763b664a12a1542c89c940daa55196e8d73e55b169cc5c99f65f", size = 3278825, upload-time = "2026-03-02T15:50:38.269Z" }, + { url = "https://files.pythonhosted.org/packages/fe/88/cb59509e4668d8001818d7355d9995be90c321313078c912420603a7cb95/sqlalchemy-2.0.48-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b19151e76620a412c2ac1c6f977ab1b9fa7ad43140178345136456d5265b32ed", size = 3295200, upload-time = "2026-03-02T15:53:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/87/dc/1609a4442aefd750ea2f32629559394ec92e89ac1d621a7f462b70f736ff/sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b193a7e29fd9fa56e502920dca47dffe60f97c863494946bd698c6058a55658", size = 3226876, upload-time = "2026-03-02T15:50:39.802Z" }, + { url = "https://files.pythonhosted.org/packages/37/c3/6ae2ab5ea2fa989fbac4e674de01224b7a9d744becaf59bb967d62e99bed/sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:36ac4ddc3d33e852da9cb00ffb08cea62ca05c39711dc67062ca2bb1fae35fd8", size = 3265045, upload-time = "2026-03-02T15:53:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/6f/82/ea4665d1bb98c50c19666e672f21b81356bd6077c4574e3d2bbb84541f53/sqlalchemy-2.0.48-cp313-cp313-win32.whl", hash = "sha256:389b984139278f97757ea9b08993e7b9d1142912e046ab7d82b3fbaeb0209131", size = 2113700, upload-time = "2026-03-02T15:54:35.825Z" }, + { url = "https://files.pythonhosted.org/packages/b7/2b/b9040bec58c58225f073f5b0c1870defe1940835549dafec680cbd58c3c3/sqlalchemy-2.0.48-cp313-cp313-win_amd64.whl", hash = "sha256:d612c976cbc2d17edfcc4c006874b764e85e990c29ce9bd411f926bbfb02b9a2", size = 2139487, upload-time = "2026-03-02T15:54:37.079Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/7b17bd50244b78a49d22cc63c969d71dc4de54567dc152a9b46f6fae40ce/sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69f5bc24904d3bc3640961cddd2523e361257ef68585d6e364166dfbe8c78fae", size = 3558851, upload-time = "2026-03-02T15:57:48.607Z" }, + { url = "https://files.pythonhosted.org/packages/20/0d/213668e9aca61d370f7d2a6449ea4ec699747fac67d4bda1bb3d129025be/sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd08b90d211c086181caed76931ecfa2bdfc83eea3cfccdb0f82abc6c4b876cb", size = 3525525, upload-time = "2026-03-02T16:04:38.058Z" }, + { url = "https://files.pythonhosted.org/packages/85/d7/a84edf412979e7d59c69b89a5871f90a49228360594680e667cb2c46a828/sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1ccd42229aaac2df431562117ac7e667d702e8e44afdb6cf0e50fa3f18160f0b", size = 3466611, upload-time = "2026-03-02T15:57:50.759Z" }, + { url = "https://files.pythonhosted.org/packages/86/55/42404ce5770f6be26a2b0607e7866c31b9a4176c819e9a7a5e0a055770be/sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0dcbc588cd5b725162c076eb9119342f6579c7f7f55057bb7e3c6ff27e13121", size = 3475812, upload-time = "2026-03-02T16:04:40.092Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ae/29b87775fadc43e627cf582fe3bda4d02e300f6b8f2747c764950d13784c/sqlalchemy-2.0.48-cp313-cp313t-win32.whl", hash = "sha256:9764014ef5e58aab76220c5664abb5d47d5bc858d9debf821e55cfdd0f128485", size = 2141335, upload-time = "2026-03-02T15:52:51.518Z" }, + { url = "https://files.pythonhosted.org/packages/91/44/f39d063c90f2443e5b46ec4819abd3d8de653893aae92df42a5c4f5843de/sqlalchemy-2.0.48-cp313-cp313t-win_amd64.whl", hash = "sha256:e2f35b4cccd9ed286ad62e0a3c3ac21e06c02abc60e20aa51a3e305a30f5fa79", size = 2173095, upload-time = "2026-03-02T15:52:52.79Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" }, +] + +[package.optional-dependencies] +asyncio = [ + { name = "greenlet" }, +] + +[[package]] +name = "starlette" +version = "0.52.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, +] + +[[package]] +name = "structlog" +version = "25.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/52/9ba0f43b686e7f3ddfeaa78ac3af750292662284b3661e91ad5494f21dbc/structlog-25.5.0.tar.gz", hash = "sha256:098522a3bebed9153d4570c6d0288abf80a031dfdb2048d59a49e9dc2190fc98", size = 1460830, upload-time = "2025-10-27T08:28:23.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl", hash = "sha256:a8453e9b9e636ec59bd9e79bbd4a72f025981b3ba0f5837aebf48f02f37a7f9f", size = 72510, upload-time = "2025-10-27T08:28:21.535Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "tabulate" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, +] + +[[package]] +name = "tblib" +version = "3.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/8a/14c15ae154895cc131174f858c707790d416c444fc69f93918adfd8c4c0b/tblib-3.2.2.tar.gz", hash = "sha256:e9a652692d91bf4f743d4a15bc174c0b76afc750fe8c7b6d195cc1c1d6d2ccec", size = 35046, upload-time = "2025-11-12T12:21:16.572Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/be/5d2d47b1fb58943194fb59dcf222f7c4e35122ec0ffe8c36e18b5d728f0b/tblib-3.2.2-py3-none-any.whl", hash = "sha256:26bdccf339bcce6a88b2b5432c988b266ebbe63a4e593f6b578b1d2e723d2b76", size = 12893, upload-time = "2025-11-12T12:21:14.407Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +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.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/46/21ea696b21f1d6d1efec8639c204bdf20fde8bafb351e1355c72c5d7de52/tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb", size = 1051565, upload-time = "2025-10-06T20:21:44.566Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d9/35c5d2d9e22bb2a5f74ba48266fb56c63d76ae6f66e02feb628671c0283e/tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa", size = 995284, upload-time = "2025-10-06T20:21:45.622Z" }, + { url = "https://files.pythonhosted.org/packages/01/84/961106c37b8e49b9fdcf33fe007bb3a8fdcc380c528b20cc7fbba80578b8/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc", size = 1129201, upload-time = "2025-10-06T20:21:47.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/d0/3d9275198e067f8b65076a68894bb52fd253875f3644f0a321a720277b8a/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded", size = 1152444, upload-time = "2025-10-06T20:21:48.139Z" }, + { url = "https://files.pythonhosted.org/packages/78/db/a58e09687c1698a7c592e1038e01c206569b86a0377828d51635561f8ebf/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd", size = 1195080, upload-time = "2025-10-06T20:21:49.246Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/a9e4d2bf91d515c0f74afc526fd773a812232dd6cda33ebea7f531202325/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967", size = 1255240, upload-time = "2025-10-06T20:21:50.274Z" }, + { url = "https://files.pythonhosted.org/packages/9d/15/963819345f1b1fb0809070a79e9dd96938d4ca41297367d471733e79c76c/tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def", size = 879422, upload-time = "2025-10-06T20:21:51.734Z" }, + { url = "https://files.pythonhosted.org/packages/a4/85/be65d39d6b647c79800fd9d29241d081d4eeb06271f383bb87200d74cf76/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8", size = 1050728, upload-time = "2025-10-06T20:21:52.756Z" }, + { url = "https://files.pythonhosted.org/packages/4a/42/6573e9129bc55c9bf7300b3a35bef2c6b9117018acca0dc760ac2d93dffe/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b", size = 994049, upload-time = "2025-10-06T20:21:53.782Z" }, + { url = "https://files.pythonhosted.org/packages/66/c5/ed88504d2f4a5fd6856990b230b56d85a777feab84e6129af0822f5d0f70/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37", size = 1129008, upload-time = "2025-10-06T20:21:54.832Z" }, + { url = "https://files.pythonhosted.org/packages/f4/90/3dae6cc5436137ebd38944d396b5849e167896fc2073da643a49f372dc4f/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad", size = 1152665, upload-time = "2025-10-06T20:21:56.129Z" }, + { url = "https://files.pythonhosted.org/packages/a3/fe/26df24ce53ffde419a42f5f53d755b995c9318908288c17ec3f3448313a3/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5", size = 1194230, upload-time = "2025-10-06T20:21:57.546Z" }, + { url = "https://files.pythonhosted.org/packages/20/cc/b064cae1a0e9fac84b0d2c46b89f4e57051a5f41324e385d10225a984c24/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3", size = 1254688, upload-time = "2025-10-06T20:21:58.619Z" }, + { url = "https://files.pythonhosted.org/packages/81/10/b8523105c590c5b8349f2587e2fdfe51a69544bd5a76295fc20f2374f470/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd", size = 878694, upload-time = "2025-10-06T20:21:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/00/61/441588ee21e6b5cdf59d6870f86beb9789e532ee9718c251b391b70c68d6/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3", size = 1050802, upload-time = "2025-10-06T20:22:00.96Z" }, + { url = "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160", size = 993995, upload-time = "2025-10-06T20:22:02.788Z" }, + { url = "https://files.pythonhosted.org/packages/a0/70/5163fe5359b943f8db9946b62f19be2305de8c3d78a16f629d4165e2f40e/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa", size = 1128948, upload-time = "2025-10-06T20:22:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/c028aa0babf77315e1cef357d4d768800c5f8a6de04d0eac0f377cb619fa/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be", size = 1151986, upload-time = "2025-10-06T20:22:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5a/886b108b766aa53e295f7216b509be95eb7d60b166049ce2c58416b25f2a/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a", size = 1194222, upload-time = "2025-10-06T20:22:06.265Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/4db272048397636ac7a078d22773dd2795b1becee7bc4922fe6207288d57/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3", size = 1255097, upload-time = "2025-10-06T20:22:07.403Z" }, + { url = "https://files.pythonhosted.org/packages/8e/32/45d02e2e0ea2be3a9ed22afc47d93741247e75018aac967b713b2941f8ea/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697", size = 879117, upload-time = "2025-10-06T20:22:08.418Z" }, + { url = "https://files.pythonhosted.org/packages/ce/76/994fc868f88e016e6d05b0da5ac24582a14c47893f4474c3e9744283f1d5/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16", size = 1050309, upload-time = "2025-10-06T20:22:10.939Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/57ef1456504c43a849821920d582a738a461b76a047f352f18c0b26c6516/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a", size = 993712, upload-time = "2025-10-06T20:22:12.115Z" }, + { url = "https://files.pythonhosted.org/packages/72/90/13da56f664286ffbae9dbcfadcc625439142675845baa62715e49b87b68b/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27", size = 1128725, upload-time = "2025-10-06T20:22:13.541Z" }, + { url = "https://files.pythonhosted.org/packages/05/df/4f80030d44682235bdaecd7346c90f67ae87ec8f3df4a3442cb53834f7e4/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb", size = 1151875, upload-time = "2025-10-06T20:22:14.559Z" }, + { url = "https://files.pythonhosted.org/packages/22/1f/ae535223a8c4ef4c0c1192e3f9b82da660be9eb66b9279e95c99288e9dab/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e", size = 1194451, upload-time = "2025-10-06T20:22:15.545Z" }, + { url = "https://files.pythonhosted.org/packages/78/a7/f8ead382fce0243cb625c4f266e66c27f65ae65ee9e77f59ea1653b6d730/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25", size = 1253794, upload-time = "2025-10-06T20:22:16.624Z" }, + { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777, upload-time = "2025-10-06T20:22:18.036Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "tomlkit" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" }, +] + +[[package]] +name = "toolz" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/d6/114b492226588d6ff54579d95847662fc69196bdeec318eb45393b24c192/toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b", size = 52613, upload-time = "2025-10-17T04:03:21.661Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093, upload-time = "2025-10-17T04:03:20.435Z" }, +] + +[[package]] +name = "torch" +version = "2.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "setuptools", marker = "python_full_version >= '3.12'" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/8b/4b61d6e13f7108f36910df9ab4b58fd389cc2520d54d81b88660804aad99/torch-2.10.0-2-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:418997cb02d0a0f1497cf6a09f63166f9f5df9f3e16c8a716ab76a72127c714f", size = 79423467, upload-time = "2026-02-10T21:44:48.711Z" }, + { url = "https://files.pythonhosted.org/packages/d3/54/a2ba279afcca44bbd320d4e73675b282fcee3d81400ea1b53934efca6462/torch-2.10.0-2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:13ec4add8c3faaed8d13e0574f5cd4a323c11655546f91fbe6afa77b57423574", size = 79498202, upload-time = "2026-02-10T21:44:52.603Z" }, + { url = "https://files.pythonhosted.org/packages/ec/23/2c9fe0c9c27f7f6cb865abcea8a4568f29f00acaeadfc6a37f6801f84cb4/torch-2.10.0-2-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:e521c9f030a3774ed770a9c011751fb47c4d12029a3d6522116e48431f2ff89e", size = 79498254, upload-time = "2026-02-10T21:44:44.095Z" }, + { url = "https://files.pythonhosted.org/packages/78/89/f5554b13ebd71e05c0b002f95148033e730d3f7067f67423026cc9c69410/torch-2.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3282d9febd1e4e476630a099692b44fdc214ee9bf8ee5377732d9d9dfe5712e4", size = 145992610, upload-time = "2026-01-21T16:25:26.327Z" }, + { url = "https://files.pythonhosted.org/packages/ae/30/a3a2120621bf9c17779b169fc17e3dc29b230c29d0f8222f499f5e159aa8/torch-2.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a2f9edd8dbc99f62bc4dfb78af7bf89499bca3d753423ac1b4e06592e467b763", size = 915607863, upload-time = "2026-01-21T16:25:06.696Z" }, + { url = "https://files.pythonhosted.org/packages/6f/3d/c87b33c5f260a2a8ad68da7147e105f05868c281c63d65ed85aa4da98c66/torch-2.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:29b7009dba4b7a1c960260fc8ac85022c784250af43af9fb0ebafc9883782ebd", size = 113723116, upload-time = "2026-01-21T16:25:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/61/d8/15b9d9d3a6b0c01b883787bd056acbe5cc321090d4b216d3ea89a8fcfdf3/torch-2.10.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:b7bd80f3477b830dd166c707c5b0b82a898e7b16f59a7d9d42778dd058272e8b", size = 79423461, upload-time = "2026-01-21T16:24:50.266Z" }, + { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" }, + { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" }, + { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5c/dee910b87c4d5c0fcb41b50839ae04df87c1cfc663cf1b5fca7ea565eeaa/torch-2.10.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:6d3707a61863d1c4d6ebba7be4ca320f42b869ee657e9b2c21c736bf17000294", size = 79498198, upload-time = "2026-01-21T16:24:34.704Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6f/f2e91e34e3fcba2e3fc8d8f74e7d6c22e74e480bbd1db7bc8900fdf3e95c/torch-2.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5c4d217b14741e40776dd7074d9006fd28b8a97ef5654db959d8635b2fe5f29b", size = 146004247, upload-time = "2026-01-21T16:24:29.335Z" }, + { url = "https://files.pythonhosted.org/packages/98/fb/5160261aeb5e1ee12ee95fe599d0541f7c976c3701d607d8fc29e623229f/torch-2.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6b71486353fce0f9714ca0c9ef1c850a2ae766b409808acd58e9678a3edb7738", size = 915716445, upload-time = "2026-01-21T16:22:45.353Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/502fb1b41e6d868e8deb5b0e3ae926bbb36dab8ceb0d1b769b266ad7b0c3/torch-2.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2ee399c644dc92ef7bc0d4f7e74b5360c37cdbe7c5ba11318dda49ffac2bc57", size = 113757050, upload-time = "2026-01-21T16:24:19.204Z" }, + { url = "https://files.pythonhosted.org/packages/1a/0b/39929b148f4824bc3ad6f9f72a29d4ad865bcf7ebfc2fa67584773e083d2/torch-2.10.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:3202429f58309b9fa96a614885eace4b7995729f44beb54d3e4a47773649d382", size = 79851305, upload-time = "2026-01-21T16:24:09.209Z" }, + { url = "https://files.pythonhosted.org/packages/d8/14/21fbce63bc452381ba5f74a2c0a959fdf5ad5803ccc0c654e752e0dbe91a/torch-2.10.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:aae1b29cd68e50a9397f5ee897b9c24742e9e306f88a807a27d617f07adb3bd8", size = 146005472, upload-time = "2026-01-21T16:22:29.022Z" }, + { url = "https://files.pythonhosted.org/packages/54/fd/b207d1c525cb570ef47f3e9f836b154685011fce11a2f444ba8a4084d042/torch-2.10.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6021db85958db2f07ec94e1bc77212721ba4920c12a18dc552d2ae36a3eb163f", size = 915612644, upload-time = "2026-01-21T16:21:47.019Z" }, + { url = "https://files.pythonhosted.org/packages/36/53/0197f868c75f1050b199fe58f9bf3bf3aecac9b4e85cc9c964383d745403/torch-2.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff43db38af76fda183156153983c9a096fc4c78d0cd1e07b14a2314c7f01c2c8", size = 113997015, upload-time = "2026-01-21T16:23:00.767Z" }, + { url = "https://files.pythonhosted.org/packages/0e/13/e76b4d9c160e89fff48bf16b449ea324bda84745d2ab30294c37c2434c0d/torch-2.10.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:cdf2a523d699b70d613243211ecaac14fe9c5df8a0b0a9c02add60fb2a413e0f", size = 79498248, upload-time = "2026-01-21T16:23:09.315Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, +] + +[[package]] +name = "transformers" +version = "4.57.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912, upload-time = "2026-01-16T10:38:39.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" }, +] + +[[package]] +name = "tree-sitter" +version = "0.21.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/39/9e/b7cb190aa08e4ea387f2b1531da03efb4b8b033426753c0b97e3698645f6/tree-sitter-0.21.3.tar.gz", hash = "sha256:b5de3028921522365aa864d95b3c41926e0ba6a85ee5bd000e10dc49b0766988", size = 155688, upload-time = "2024-03-26T10:53:35.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/b5/72657d5874d7f0a722c0288f04e5e2bc33d7715b13a858885b6593047dce/tree_sitter-0.21.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54b22c3c2aab3e3639a4b255d9df8455da2921d050c4829b6a5663b057f10db5", size = 133429, upload-time = "2024-03-26T10:52:46.345Z" }, + { url = "https://files.pythonhosted.org/packages/d3/64/c5d397efbb6d0dbed4254cd2ca389ed186a2e1e7e32661059f6eeaaf6424/tree_sitter-0.21.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab6e88c1e2d5e84ff0f9e5cd83f21b8e5074ad292a2cf19df3ba31d94fbcecd4", size = 126088, upload-time = "2024-03-26T10:52:47.759Z" }, + { url = "https://files.pythonhosted.org/packages/ba/88/941669acc140f94e6c6196d6d8676ac4cd57c3b3fbc1ee61bb11c1b2da71/tree_sitter-0.21.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3fd34ed4cd5db445bc448361b5da46a2a781c648328dc5879d768f16a46771", size = 487879, upload-time = "2024-03-26T10:52:49.091Z" }, + { url = "https://files.pythonhosted.org/packages/29/4e/798154f2846d620bf9fa3bc244e056d4858f2108f834656bf9f1219d4f30/tree_sitter-0.21.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fabc7182f6083269ce3cfcad202fe01516aa80df64573b390af6cd853e8444a1", size = 498776, upload-time = "2024-03-26T10:52:50.709Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d1/05ea77487bc7a3946d0e80fb6c5cb61515953f5e7a4f6804b98e113ed4b0/tree_sitter-0.21.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f874c3f7d2a2faf5c91982dc7d88ff2a8f183a21fe475c29bee3009773b0558", size = 483348, upload-time = "2024-03-26T10:52:52.267Z" }, + { url = "https://files.pythonhosted.org/packages/42/fa/bf938e7c6afbc368d503deeda060891c3dba57e2d1166e4b884271f55616/tree_sitter-0.21.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ee61ee3b7a4eedf9d8f1635c68ba4a6fa8c46929601fc48a907c6cfef0cfbcb2", size = 493757, upload-time = "2024-03-26T10:52:54.845Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a7/98da36a6eab22f5729989c9e0137b1b04cbe368d1e024fccd72c0b00719b/tree_sitter-0.21.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b7256c723642de1c05fbb776b27742204a2382e337af22f4d9e279d77df7aa2", size = 109735, upload-time = "2024-03-26T10:52:57.243Z" }, + { url = "https://files.pythonhosted.org/packages/81/e1/cceb06eae617a6bf5eeeefa9813d9fd57d89b50f526ce02486a336bcd2a9/tree_sitter-0.21.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:669b3e5a52cb1e37d60c7b16cc2221c76520445bb4f12dd17fd7220217f5abf3", size = 133640, upload-time = "2024-03-26T10:52:59.135Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ce/ac14e5cbb0f30b7bd338122491ee2b8e6c0408cfe26741cbd66fa9b53d35/tree_sitter-0.21.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2aa2a5099a9f667730ff26d57533cc893d766667f4d8a9877e76a9e74f48f0d3", size = 125954, upload-time = "2024-03-26T10:53:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/c2/df/76dbf830126e566c48db0d1bf2bef3f9d8cac938302a9b0f762ded8206c2/tree_sitter-0.21.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3e06ae2a517cf6f1abb682974f76fa760298e6d5a3ecf2cf140c70f898adf0", size = 490092, upload-time = "2024-03-26T10:53:03.144Z" }, + { url = "https://files.pythonhosted.org/packages/ec/87/0c3593552cb0d09ab6271d37fc0e6a9476919d2a975661d709d4b3289fc7/tree_sitter-0.21.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af992dfe08b4fefcfcdb40548d0d26d5d2e0a0f2d833487372f3728cd0772b48", size = 502155, upload-time = "2024-03-26T10:53:04.76Z" }, + { url = "https://files.pythonhosted.org/packages/05/92/b2cb22cf52c18fcc95662897f380cf230c443dfc9196b872aad5948b7bb3/tree_sitter-0.21.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c7cbab1dd9765138505c4a55e2aa857575bac4f1f8a8b0457744a4fefa1288e6", size = 486020, upload-time = "2024-03-26T10:53:06.414Z" }, + { url = "https://files.pythonhosted.org/packages/4a/ea/69b543538a46d763f3e787234d1617b718ab90f32ffa676ca856f1d9540e/tree_sitter-0.21.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1e66aeb457d1529370fcb0997ae5584c6879e0e662f1b11b2f295ea57e22f54", size = 496348, upload-time = "2024-03-26T10:53:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/eb/4f/df4ea84476443021707b537217c32147ccccbc3e10c17b216a969991e1b3/tree_sitter-0.21.3-cp312-cp312-win_amd64.whl", hash = "sha256:013c750252dc3bd0e069d82e9658de35ed50eecf31c6586d0de7f942546824c5", size = 109771, upload-time = "2024-03-26T10:53:10.342Z" }, +] + +[[package]] +name = "tree-sitter-java" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/33/627a1bc82178131057bfad7ba1178f09979ac6ee8034915eb3caf0ff6088/tree_sitter_java-0.21.0-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d30fb39af6590f6be877ff8d39c7e193f37594375b8fcdda55babd264411616b", size = 75795, upload-time = "2024-04-07T18:43:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/4e/5a/c274c4b338b77035804905d216c73dbf7e672d5b8ef55e89ec47fa62f27a/tree_sitter_java-0.21.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:696391968cdc467f97e525fbe43790c2d5ba46bf446376eb30d5c20b5c9d795a", size = 78061, upload-time = "2024-04-07T18:43:57.438Z" }, + { url = "https://files.pythonhosted.org/packages/90/27/1fb08e41074ee0cf26741f852ab995878974f63c5ce32df929507683417b/tree_sitter_java-0.21.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b82318982531a473c598601d73956b0b1f9e608d39e427ba8c1a59f2d6da262", size = 125576, upload-time = "2024-04-07T18:43:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/60/e7/b7dee7289ff66af83bf4c784847c9ded95276794d8d070495ca4b41d963d/tree_sitter_java-0.21.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9c01f48ec3a3d4b55fb2c56b7cad6ebf94dba568d690b45d966731859485dd4", size = 116990, upload-time = "2024-04-07T18:44:00.859Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e3/591d561cc52a7b672b3c0836696b97222673ee7b0d2785b5ee26064dce1f/tree_sitter_java-0.21.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d83ca51b26826550051c53468ec74f5b570b4afb4d4520df0aa2a35b52de2289", size = 128126, upload-time = "2024-04-07T18:44:02.731Z" }, + { url = "https://files.pythonhosted.org/packages/eb/48/fbf338a749bd6e7e58bf9c30de5d7afb697a8ac5263cb68e79bdf18a6cfa/tree_sitter_java-0.21.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:8afb56c90048272b079235b82fc2a4a69b058b4ace206d9475cbad2eb143f40a", size = 119512, upload-time = "2024-04-07T18:44:04.682Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e2/a84f1b286197645cbedd360971ed0da4ad1ff21be236d927e62b679186de/tree_sitter_java-0.21.0-cp38-abi3-win_amd64.whl", hash = "sha256:6534fac27a93160a2b27a0c77f22a7c91f0aee2dba9d4cdbf835bf509ddfbf4f", size = 74376, upload-time = "2024-04-07T18:44:06.002Z" }, +] + +[[package]] +name = "tree-sitter-javascript" +version = "0.21.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/f3/16e8566c46fe14965386284296e2f83f0e06b16a613d1d518b434844180b/tree-sitter-javascript-0.21.4.tar.gz", hash = "sha256:5ae97db218c22f16f1fd1108d77c4017b453addc36041136779c99800f23ff20", size = 109366, upload-time = "2024-07-06T00:52:05.796Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/44/c677dd586079a27b5237786e14713fdbff9fc556cea968658e09e26fa472/tree_sitter_javascript-0.21.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e0f1d26ec85cc66d56fb25fd41ce499dc5c4a60b478a91754684e2289433daae", size = 57025, upload-time = "2024-07-06T00:51:56.957Z" }, + { url = "https://files.pythonhosted.org/packages/ef/49/a1dd762cfe11dbaabdcf5abb46dcf8650d89e456466cc569164bdc921d11/tree_sitter_javascript-0.21.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:e9172dc9e59649d7598c6509103db1648e7187c2bcb39c34222fc052b9db0ac4", size = 60305, upload-time = "2024-07-06T00:51:58.367Z" }, + { url = "https://files.pythonhosted.org/packages/f5/eb/1f7eb01fb0b62270c75eab9ac883a65226acfc63e76973cb21abee0ccad0/tree_sitter_javascript-0.21.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d45bd39ce931b164f84cfb6a186df504e38c6f91f541e2e60d5a40eb9d574005", size = 85520, upload-time = "2024-07-06T00:51:59.887Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e3/a9f64c23cd37e88aae0758f31502f57613aa73058fb49c1c6eb9df97d201/tree_sitter_javascript-0.21.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00ff426e9bb552abb49ce3234b083edb1a6aa73bfeea7d9bf0f6bb3d0256c4cd", size = 76624, upload-time = "2024-07-06T00:52:01.315Z" }, + { url = "https://files.pythonhosted.org/packages/61/d4/8ed6ef32244dbb652a0e433a6f357afaf91614f69159abb03e4a5f96109a/tree_sitter_javascript-0.21.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c2945bc49985ab396773e2738ae9b1e7d06950d6ad70c535c010fb9b2816a855", size = 73782, upload-time = "2024-07-06T00:52:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a1/57579a8ab9a23ea6204d54958516a0119e168960e1d34cff036b9e762abc/tree_sitter_javascript-0.21.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fc87d07f4c6a7067d4e0f004956a549c05e21eeced3287f3ea2bdd04a71a97a", size = 73276, upload-time = "2024-07-06T00:52:03.794Z" }, + { url = "https://files.pythonhosted.org/packages/19/e5/0681f027261093609cc56e5ca5e3c8e7eeee16e01081e0eee6c8d02fd2ce/tree_sitter_javascript-0.21.4-cp38-abi3-win_amd64.whl", hash = "sha256:2843b0e81564d8176922ef2b40db128a4de026606d6b1d22a06efb8e8a5c01b8", size = 60417, upload-time = "2024-07-06T00:52:04.7Z" }, +] + +[[package]] +name = "triton" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/12/b05ba554d2c623bffa59922b94b0775673de251f468a9609bc9e45de95e9/triton-3.6.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8e323d608e3a9bfcc2d9efcc90ceefb764a82b99dea12a86d643c72539ad5d3", size = 188214640, upload-time = "2026-01-20T16:00:35.869Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a8/cdf8b3e4c98132f965f88c2313a4b493266832ad47fb52f23d14d4f86bb5/triton-3.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74caf5e34b66d9f3a429af689c1c7128daba1d8208df60e81106b115c00d6fca", size = 188266850, upload-time = "2026-01-20T16:00:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0b/37d991d8c130ce81a8728ae3c25b6e60935838e9be1b58791f5997b24a54/triton-3.6.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9", size = 188289450, upload-time = "2026-01-20T16:00:49.136Z" }, + { url = "https://files.pythonhosted.org/packages/35/f8/9c66bfc55361ec6d0e4040a0337fb5924ceb23de4648b8a81ae9d33b2b38/triton-3.6.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f", size = 188400296, upload-time = "2026-01-20T16:00:56.042Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "uuid-utils" +version = "0.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/d1/38a573f0c631c062cf42fa1f5d021d4dd3c31fb23e4376e4b56b0c9fbbed/uuid_utils-0.14.1.tar.gz", hash = "sha256:9bfc95f64af80ccf129c604fb6b8ca66c6f256451e32bc4570f760e4309c9b69", size = 22195, upload-time = "2026-02-20T22:50:38.833Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/b7/add4363039a34506a58457d96d4aa2126061df3a143eb4d042aedd6a2e76/uuid_utils-0.14.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:93a3b5dc798a54a1feb693f2d1cb4cf08258c32ff05ae4929b5f0a2ca624a4f0", size = 604679, upload-time = "2026-02-20T22:50:27.469Z" }, + { url = "https://files.pythonhosted.org/packages/dd/84/d1d0bef50d9e66d31b2019997c741b42274d53dde2e001b7a83e9511c339/uuid_utils-0.14.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ccd65a4b8e83af23eae5e56d88034b2fe7264f465d3e830845f10d1591b81741", size = 309346, upload-time = "2026-02-20T22:50:31.857Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ed/b6d6fd52a6636d7c3eddf97d68da50910bf17cd5ac221992506fb56cf12e/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b56b0cacd81583834820588378e432b0696186683b813058b707aedc1e16c4b1", size = 344714, upload-time = "2026-02-20T22:50:42.642Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a7/a19a1719fb626fe0b31882db36056d44fe904dc0cf15b06fdf56b2679cf7/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb3cf14de789097320a3c56bfdfdd51b1225d11d67298afbedee7e84e3837c96", size = 350914, upload-time = "2026-02-20T22:50:36.487Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fc/f6690e667fdc3bb1a73f57951f97497771c56fe23e3d302d7404be394d4f/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e0854a90d67f4b0cc6e54773deb8be618f4c9bad98d3326f081423b5d14fae", size = 482609, upload-time = "2026-02-20T22:50:37.511Z" }, + { url = "https://files.pythonhosted.org/packages/54/6e/dcd3fa031320921a12ec7b4672dea3bd1dd90ddffa363a91831ba834d559/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6743ba194de3910b5feb1a62590cd2587e33a73ab6af8a01b642ceb5055862", size = 345699, upload-time = "2026-02-20T22:50:46.87Z" }, + { url = "https://files.pythonhosted.org/packages/04/28/e5220204b58b44ac0047226a9d016a113fde039280cc8732d9e6da43b39f/uuid_utils-0.14.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:043fb58fde6cf1620a6c066382f04f87a8e74feb0f95a585e4ed46f5d44af57b", size = 372205, upload-time = "2026-02-20T22:50:28.438Z" }, + { url = "https://files.pythonhosted.org/packages/c7/d9/3d2eb98af94b8dfffc82b6a33b4dfc87b0a5de2c68a28f6dde0db1f8681b/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c915d53f22945e55fe0d3d3b0b87fd965a57f5fd15666fd92d6593a73b1dd297", size = 521836, upload-time = "2026-02-20T22:50:23.057Z" }, + { url = "https://files.pythonhosted.org/packages/a8/15/0eb106cc6fe182f7577bc0ab6e2f0a40be247f35c5e297dbf7bbc460bd02/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:0972488e3f9b449e83f006ead5a0e0a33ad4a13e4462e865b7c286ab7d7566a3", size = 625260, upload-time = "2026-02-20T22:50:25.949Z" }, + { url = "https://files.pythonhosted.org/packages/3c/17/f539507091334b109e7496830af2f093d9fc8082411eafd3ece58af1f8ba/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:1c238812ae0c8ffe77d8d447a32c6dfd058ea4631246b08b5a71df586ff08531", size = 587824, upload-time = "2026-02-20T22:50:35.225Z" }, + { url = "https://files.pythonhosted.org/packages/2e/c2/d37a7b2e41f153519367d4db01f0526e0d4b06f1a4a87f1c5dfca5d70a8b/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:bec8f8ef627af86abf8298e7ec50926627e29b34fa907fcfbedb45aaa72bca43", size = 551407, upload-time = "2026-02-20T22:50:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/65/36/2d24b2cbe78547c6532da33fb8613debd3126eccc33a6374ab788f5e46e9/uuid_utils-0.14.1-cp39-abi3-win32.whl", hash = "sha256:b54d6aa6252d96bac1fdbc80d26ba71bad9f220b2724d692ad2f2310c22ef523", size = 183476, upload-time = "2026-02-20T22:50:32.745Z" }, + { url = "https://files.pythonhosted.org/packages/83/92/2d7e90df8b1a69ec4cff33243ce02b7a62f926ef9e2f0eca5a026889cd73/uuid_utils-0.14.1-cp39-abi3-win_amd64.whl", hash = "sha256:fc27638c2ce267a0ce3e06828aff786f91367f093c80625ee21dad0208e0f5ba", size = 187147, upload-time = "2026-02-20T22:50:45.807Z" }, + { url = "https://files.pythonhosted.org/packages/d9/26/529f4beee17e5248e37e0bc17a2761d34c0fa3b1e5729c88adb2065bae6e/uuid_utils-0.14.1-cp39-abi3-win_arm64.whl", hash = "sha256:b04cb49b42afbc4ff8dbc60cf054930afc479d6f4dd7f1ec3bbe5dbfdde06b7a", size = 188132, upload-time = "2026-02-20T22:50:41.718Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/6c64bdbf71f58ccde7919e00491812556f446a5291573af92c49a5e9aaef/uuid_utils-0.14.1-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b197cd5424cf89fb019ca7f53641d05bfe34b1879614bed111c9c313b5574cd8", size = 591617, upload-time = "2026-02-20T22:50:24.532Z" }, + { url = "https://files.pythonhosted.org/packages/d0/f0/758c3b0fb0c4871c7704fef26a5bc861de4f8a68e4831669883bebe07b0f/uuid_utils-0.14.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:12c65020ba6cb6abe1d57fcbfc2d0ea0506c67049ee031714057f5caf0f9bc9c", size = 303702, upload-time = "2026-02-20T22:50:40.687Z" }, + { url = "https://files.pythonhosted.org/packages/85/89/d91862b544c695cd58855efe3201f83894ed82fffe34500774238ab8eba7/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b5d2ad28063d422ccc2c28d46471d47b61a58de885d35113a8f18cb547e25bf", size = 337678, upload-time = "2026-02-20T22:50:39.768Z" }, + { url = "https://files.pythonhosted.org/packages/ee/6b/cf342ba8a898f1de024be0243fac67c025cad530c79ea7f89c4ce718891a/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da2234387b45fde40b0fedfee64a0ba591caeea9c48c7698ab6e2d85c7991533", size = 343711, upload-time = "2026-02-20T22:50:43.965Z" }, + { url = "https://files.pythonhosted.org/packages/b3/20/049418d094d396dfa6606b30af925cc68a6670c3b9103b23e6990f84b589/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50fffc2827348c1e48972eed3d1c698959e63f9d030aa5dd82ba451113158a62", size = 476731, upload-time = "2026-02-20T22:50:30.589Z" }, + { url = "https://files.pythonhosted.org/packages/77/a1/0857f64d53a90321e6a46a3d4cc394f50e1366132dcd2ae147f9326ca98b/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1dbe718765f70f5b7f9b7f66b6a937802941b1cc56bcf642ce0274169741e01", size = 338902, upload-time = "2026-02-20T22:50:33.927Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d0/5bf7cbf1ac138c92b9ac21066d18faf4d7e7f651047b700eb192ca4b9fdb/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:258186964039a8e36db10810c1ece879d229b01331e09e9030bc5dcabe231bd2", size = 364700, upload-time = "2026-02-20T22:50:21.732Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.41.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633, upload-time = "2026-02-16T23:07:24.1Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783, upload-time = "2026-02-16T23:07:22.357Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, + { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, + { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f8/2c5f479fb531ce2f0564eda479faecf253d886b1ab3630a39b7bf7362d46/watchfiles-1.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f57b396167a2565a4e8b5e56a5a1c537571733992b226f4f1197d79e94cf0ae5", size = 406529, upload-time = "2025-10-14T15:04:32.899Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cd/f515660b1f32f65df671ddf6f85bfaca621aee177712874dc30a97397977/watchfiles-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:421e29339983e1bebc281fab40d812742268ad057db4aee8c4d2bce0af43b741", size = 394384, upload-time = "2025-10-14T15:04:33.761Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c3/28b7dc99733eab43fca2d10f55c86e03bd6ab11ca31b802abac26b23d161/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e43d39a741e972bab5d8100b5cdacf69db64e34eb19b6e9af162bccf63c5cc6", size = 448789, upload-time = "2025-10-14T15:04:34.679Z" }, + { url = "https://files.pythonhosted.org/packages/4a/24/33e71113b320030011c8e4316ccca04194bf0cbbaeee207f00cbc7d6b9f5/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f537afb3276d12814082a2e9b242bdcf416c2e8fd9f799a737990a1dbe906e5b", size = 460521, upload-time = "2025-10-14T15:04:35.963Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c3/3c9a55f255aa57b91579ae9e98c88704955fa9dac3e5614fb378291155df/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2cd9e04277e756a2e2d2543d65d1e2166d6fd4c9b183f8808634fda23f17b14", size = 488722, upload-time = "2025-10-14T15:04:37.091Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/506447b73eb46c120169dc1717fe2eff07c234bb3232a7200b5f5bd816e9/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3f58818dc0b07f7d9aa7fe9eb1037aecb9700e63e1f6acfed13e9fef648f5d", size = 596088, upload-time = "2025-10-14T15:04:38.39Z" }, + { url = "https://files.pythonhosted.org/packages/82/ab/5f39e752a9838ec4d52e9b87c1e80f1ee3ccdbe92e183c15b6577ab9de16/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb9f66367023ae783551042d31b1d7fd422e8289eedd91f26754a66f44d5cff", size = 472923, upload-time = "2025-10-14T15:04:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/af/b9/a419292f05e302dea372fa7e6fda5178a92998411f8581b9830d28fb9edb/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aebfd0861a83e6c3d1110b78ad54704486555246e542be3e2bb94195eabb2606", size = 456080, upload-time = "2025-10-14T15:04:40.643Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c3/d5932fd62bde1a30c36e10c409dc5d54506726f08cb3e1d8d0ba5e2bc8db/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5fac835b4ab3c6487b5dbad78c4b3724e26bcc468e886f8ba8cc4306f68f6701", size = 629432, upload-time = "2025-10-14T15:04:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/f7/77/16bddd9779fafb795f1a94319dc965209c5641db5bf1edbbccace6d1b3c0/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:399600947b170270e80134ac854e21b3ccdefa11a9529a3decc1327088180f10", size = 623046, upload-time = "2025-10-14T15:04:42.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/ef/f2ecb9a0f342b4bfad13a2787155c6ee7ce792140eac63a34676a2feeef2/watchfiles-1.1.1-cp311-cp311-win32.whl", hash = "sha256:de6da501c883f58ad50db3a32ad397b09ad29865b5f26f64c24d3e3281685849", size = 271473, upload-time = "2025-10-14T15:04:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/94/bc/f42d71125f19731ea435c3948cad148d31a64fccde3867e5ba4edee901f9/watchfiles-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:35c53bd62a0b885bf653ebf6b700d1bf05debb78ad9292cf2a942b23513dc4c4", size = 287598, upload-time = "2025-10-14T15:04:44.516Z" }, + { url = "https://files.pythonhosted.org/packages/57/c9/a30f897351f95bbbfb6abcadafbaca711ce1162f4db95fc908c98a9165f3/watchfiles-1.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:57ca5281a8b5e27593cb7d82c2ac927ad88a96ed406aa446f6344e4328208e9e", size = 277210, upload-time = "2025-10-14T15:04:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" }, + { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" }, + { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" }, + { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" }, + { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" }, + { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" }, + { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" }, + { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, + { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, + { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, + { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, + { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8e/e500f8b0b77be4ff753ac94dc06b33d8f0d839377fee1b78e8c8d8f031bf/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db476ab59b6765134de1d4fe96a1a9c96ddf091683599be0f26147ea1b2e4b88", size = 408250, upload-time = "2025-10-14T15:06:10.264Z" }, + { url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, +] + +[[package]] +name = "websockets" +version = "16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, + { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, + { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, + { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, + { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, + { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, + { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, + { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, + { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, + { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, + { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, + { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, + { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, + { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, + { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, + { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, + { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, + { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, + { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, + { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, + { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, + { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, + { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, +] + +[[package]] +name = "werkzeug" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/f1/ee81806690a87dab5f5653c1f146c92bc066d7f4cebc603ef88eb9e13957/werkzeug-3.1.6.tar.gz", hash = "sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25", size = 864736, upload-time = "2026-02-19T15:17:18.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/ec/d58832f89ede95652fd01f4f24236af7d32b70cab2196dfcc2d2fd13c5c2/werkzeug-3.1.6-py3-none-any.whl", hash = "sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131", size = 225166, upload-time = "2026-02-19T15:17:17.475Z" }, +] + +[[package]] +name = "wikipedia" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/35/25e68fbc99e672127cc6fbb14b8ec1ba3dfef035bf1e4c90f78f24a80b7d/wikipedia-1.4.0.tar.gz", hash = "sha256:db0fad1829fdd441b1852306e9856398204dc0786d2996dd2e0c8bb8e26133b2", size = 27748, upload-time = "2014-11-15T15:59:49.808Z" } + +[[package]] +name = "wrapt" +version = "1.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, + { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, + { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, + { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, + { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, + { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, + { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, + { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, + { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, + { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, + { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +] + +[[package]] +name = "xmltodict" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" }, +] + +[[package]] +name = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, + { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, + { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, + { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, + { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, + { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, + { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, +] + +[[package]] +name = "yarl" +version = "1.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/aa/60da938b8f0997ba3a911263c40d82b6f645a67902a490b46f3355e10fae/yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", size = 123641, upload-time = "2026-03-01T22:04:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/24/84/e237607faf4e099dbb8a4f511cfd5efcb5f75918baad200ff7380635631b/yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", size = 86248, upload-time = "2026-03-01T22:04:44.757Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", size = 85988, upload-time = "2026-03-01T22:04:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, + { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, + { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, + { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, + { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, + { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1c/9a1979aec4a81896d597bcb2177827f2dbee3f5b7cc48b2d0dadb644b41d/yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", size = 82602, upload-time = "2026-03-01T22:05:08.444Z" }, + { url = "https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", size = 87461, upload-time = "2026-03-01T22:05:10.145Z" }, + { url = "https://files.pythonhosted.org/packages/93/95/07e3553fe6f113e6864a20bdc53a78113cda3b9ced8784ee52a52c9f80d8/yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", size = 82336, upload-time = "2026-03-01T22:05:11.554Z" }, + { url = "https://files.pythonhosted.org/packages/88/8a/94615bc31022f711add374097ad4144d569e95ff3c38d39215d07ac153a0/yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", size = 124737, upload-time = "2026-03-01T22:05:12.897Z" }, + { url = "https://files.pythonhosted.org/packages/e3/6f/c6554045d59d64052698add01226bc867b52fe4a12373415d7991fdca95d/yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", size = 87029, upload-time = "2026-03-01T22:05:14.376Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/725ecc166d53438bc88f76822ed4b1e3b10756e790bafd7b523fe97c322d/yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", size = 86310, upload-time = "2026-03-01T22:05:15.71Z" }, + { url = "https://files.pythonhosted.org/packages/99/30/58260ed98e6ff7f90ba84442c1ddd758c9170d70327394a6227b310cd60f/yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8", size = 97587, upload-time = "2026-03-01T22:05:17.384Z" }, + { url = "https://files.pythonhosted.org/packages/76/0a/8b08aac08b50682e65759f7f8dde98ae8168f72487e7357a5d684c581ef9/yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072", size = 92528, upload-time = "2026-03-01T22:05:18.804Z" }, + { url = "https://files.pythonhosted.org/packages/52/07/0b7179101fe5f8385ec6c6bb5d0cb9f76bd9fb4a769591ab6fb5cdbfc69a/yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8", size = 105339, upload-time = "2026-03-01T22:05:20.235Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/36d82869ab5ec829ca8574dfcb92b51286fcfb1e9c7a73659616362dc880/yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7", size = 105061, upload-time = "2026-03-01T22:05:22.268Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/868e5c3364b6cee19ff3e1a122194fa4ce51def02c61023970442162859e/yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51", size = 100132, upload-time = "2026-03-01T22:05:23.638Z" }, + { url = "https://files.pythonhosted.org/packages/cf/26/9c89acf82f08a52cb52d6d39454f8d18af15f9d386a23795389d1d423823/yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67", size = 99289, upload-time = "2026-03-01T22:05:25.749Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/5b0db00d2cb056922356104468019c0a132e89c8d3ab67d8ede9f4483d2a/yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7", size = 96950, upload-time = "2026-03-01T22:05:27.318Z" }, + { url = "https://files.pythonhosted.org/packages/f6/40/10fa93811fd439341fad7e0718a86aca0de9548023bbb403668d6555acab/yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d", size = 93960, upload-time = "2026-03-01T22:05:28.738Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d2/8ae2e6cd77d0805f4526e30ec43b6f9a3dfc542d401ac4990d178e4bf0cf/yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760", size = 104703, upload-time = "2026-03-01T22:05:30.438Z" }, + { url = "https://files.pythonhosted.org/packages/2f/0c/b3ceacf82c3fe21183ce35fa2acf5320af003d52bc1fcf5915077681142e/yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2", size = 98325, upload-time = "2026-03-01T22:05:31.835Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e0/12900edd28bdab91a69bd2554b85ad7b151f64e8b521fe16f9ad2f56477a/yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86", size = 105067, upload-time = "2026-03-01T22:05:33.358Z" }, + { url = "https://files.pythonhosted.org/packages/15/61/74bb1182cf79c9bbe4eb6b1f14a57a22d7a0be5e9cedf8e2d5c2086474c3/yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34", size = 100285, upload-time = "2026-03-01T22:05:35.4Z" }, + { url = "https://files.pythonhosted.org/packages/69/7f/cd5ef733f2550de6241bd8bd8c3febc78158b9d75f197d9c7baa113436af/yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d", size = 82359, upload-time = "2026-03-01T22:05:36.811Z" }, + { url = "https://files.pythonhosted.org/packages/f5/be/25216a49daeeb7af2bec0db22d5e7df08ed1d7c9f65d78b14f3b74fd72fc/yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e", size = 87674, upload-time = "2026-03-01T22:05:38.171Z" }, + { url = "https://files.pythonhosted.org/packages/d2/35/aeab955d6c425b227d5b7247eafb24f2653fedc32f95373a001af5dfeb9e/yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9", size = 81879, upload-time = "2026-03-01T22:05:40.006Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4b/a0a6e5d0ee8a2f3a373ddef8a4097d74ac901ac363eea1440464ccbe0898/yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", size = 123796, upload-time = "2026-03-01T22:05:41.412Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/8925d68af039b835ae876db5838e82e76ec87b9782ecc97e192b809c4831/yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", size = 86547, upload-time = "2026-03-01T22:05:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", size = 85854, upload-time = "2026-03-01T22:05:44.85Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f4/4e30b250927ffdab4db70da08b9b8d2194d7c7b400167b8fbeca1e4701ca/yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", size = 98351, upload-time = "2026-03-01T22:05:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/86/fc/4118c5671ea948208bdb1492d8b76bdf1453d3e73df051f939f563e7dcc5/yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", size = 92711, upload-time = "2026-03-01T22:05:48.316Z" }, + { url = "https://files.pythonhosted.org/packages/56/11/1ed91d42bd9e73c13dc9e7eb0dd92298d75e7ac4dd7f046ad0c472e231cd/yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", size = 106014, upload-time = "2026-03-01T22:05:50.028Z" }, + { url = "https://files.pythonhosted.org/packages/ce/c9/74e44e056a23fbc33aca71779ef450ca648a5bc472bdad7a82339918f818/yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", size = 105557, upload-time = "2026-03-01T22:05:51.416Z" }, + { url = "https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", size = 101559, upload-time = "2026-03-01T22:05:52.872Z" }, + { url = "https://files.pythonhosted.org/packages/72/59/c5b8d94b14e3d3c2a9c20cb100119fd534ab5a14b93673ab4cc4a4141ea5/yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", size = 100502, upload-time = "2026-03-01T22:05:54.954Z" }, + { url = "https://files.pythonhosted.org/packages/77/4f/96976cb54cbfc5c9fd73ed4c51804f92f209481d1fb190981c0f8a07a1d7/yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", size = 98027, upload-time = "2026-03-01T22:05:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/63/6e/904c4f476471afdbad6b7e5b70362fb5810e35cd7466529a97322b6f5556/yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", size = 95369, upload-time = "2026-03-01T22:05:58.141Z" }, + { url = "https://files.pythonhosted.org/packages/9d/40/acfcdb3b5f9d68ef499e39e04d25e141fe90661f9d54114556cf83be8353/yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", size = 105565, upload-time = "2026-03-01T22:06:00.286Z" }, + { url = "https://files.pythonhosted.org/packages/5e/c6/31e28f3a6ba2869c43d124f37ea5260cac9c9281df803c354b31f4dd1f3c/yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", size = 99813, upload-time = "2026-03-01T22:06:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/08/1f/6f65f59e72d54aa467119b63fc0b0b1762eff0232db1f4720cd89e2f4a17/yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", size = 105632, upload-time = "2026-03-01T22:06:03.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c4/18b178a69935f9e7a338127d5b77d868fdc0f0e49becd286d51b3a18c61d/yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", size = 101895, upload-time = "2026-03-01T22:06:04.651Z" }, + { url = "https://files.pythonhosted.org/packages/8f/54/f5b870b5505663911dba950a8e4776a0dbd51c9c54c0ae88e823e4b874a0/yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", size = 82356, upload-time = "2026-03-01T22:06:06.04Z" }, + { url = "https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", size = 87515, upload-time = "2026-03-01T22:06:08.107Z" }, + { url = "https://files.pythonhosted.org/packages/00/fd/7e1c66efad35e1649114fa13f17485f62881ad58edeeb7f49f8c5e748bf9/yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", size = 81785, upload-time = "2026-03-01T22:06:10.181Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fc/119dd07004f17ea43bb91e3ece6587759edd7519d6b086d16bfbd3319982/yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", size = 130719, upload-time = "2026-03-01T22:06:11.708Z" }, + { url = "https://files.pythonhosted.org/packages/e6/0d/9f2348502fbb3af409e8f47730282cd6bc80dec6630c1e06374d882d6eb2/yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", size = 89690, upload-time = "2026-03-01T22:06:13.429Z" }, + { url = "https://files.pythonhosted.org/packages/50/93/e88f3c80971b42cfc83f50a51b9d165a1dbf154b97005f2994a79f212a07/yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", size = 89851, upload-time = "2026-03-01T22:06:15.53Z" }, + { url = "https://files.pythonhosted.org/packages/1c/07/61c9dd8ba8f86473263b4036f70fb594c09e99c0d9737a799dfd8bc85651/yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", size = 95874, upload-time = "2026-03-01T22:06:17.553Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e9/f9ff8ceefba599eac6abddcfb0b3bee9b9e636e96dbf54342a8577252379/yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", size = 88710, upload-time = "2026-03-01T22:06:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/eb/78/0231bfcc5d4c8eec220bc2f9ef82cb4566192ea867a7c5b4148f44f6cbcd/yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", size = 101033, upload-time = "2026-03-01T22:06:21.203Z" }, + { url = "https://files.pythonhosted.org/packages/cd/9b/30ea5239a61786f18fd25797151a17fbb3be176977187a48d541b5447dd4/yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", size = 100817, upload-time = "2026-03-01T22:06:22.738Z" }, + { url = "https://files.pythonhosted.org/packages/62/e2/a4980481071791bc83bce2b7a1a1f7adcabfa366007518b4b845e92eeee3/yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", size = 97482, upload-time = "2026-03-01T22:06:24.21Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1e/304a00cf5f6100414c4b5a01fc7ff9ee724b62158a08df2f8170dfc72a2d/yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", size = 95949, upload-time = "2026-03-01T22:06:25.697Z" }, + { url = "https://files.pythonhosted.org/packages/68/03/093f4055ed4cae649ac53bca3d180bd37102e9e11d048588e9ab0c0108d0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", size = 95839, upload-time = "2026-03-01T22:06:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/b9/28/4c75ebb108f322aa8f917ae10a8ffa4f07cae10a8a627b64e578617df6a0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", size = 90696, upload-time = "2026-03-01T22:06:29.048Z" }, + { url = "https://files.pythonhosted.org/packages/23/9c/42c2e2dd91c1a570402f51bdf066bfdb1241c2240ba001967bad778e77b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", size = 100865, upload-time = "2026-03-01T22:06:30.525Z" }, + { url = "https://files.pythonhosted.org/packages/74/05/1bcd60a8a0a914d462c305137246b6f9d167628d73568505fce3f1cb2e65/yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", size = 96234, upload-time = "2026-03-01T22:06:32.692Z" }, + { url = "https://files.pythonhosted.org/packages/90/b2/f52381aac396d6778ce516b7bc149c79e65bfc068b5de2857ab69eeea3b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", size = 100295, upload-time = "2026-03-01T22:06:34.268Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/638bae5bbf1113a659b2435d8895474598afe38b4a837103764f603aba56/yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", size = 97784, upload-time = "2026-03-01T22:06:35.864Z" }, + { url = "https://files.pythonhosted.org/packages/80/25/a3892b46182c586c202629fc2159aa13975d3741d52ebd7347fd501d48d5/yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", size = 88313, upload-time = "2026-03-01T22:06:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/43/68/8c5b36aa5178900b37387937bc2c2fe0e9505537f713495472dcf6f6fccc/yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", size = 94932, upload-time = "2026-03-01T22:06:39.579Z" }, + { url = "https://files.pythonhosted.org/packages/c6/cc/d79ba8292f51f81f4dc533a8ccfb9fc6992cabf0998ed3245de7589dc07c/yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", size = 84786, upload-time = "2026-03-01T22:06:41.988Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, +] + +[[package]] +name = "yq" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "pyyaml" }, + { name = "tomlkit" }, + { name = "xmltodict" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/6a/eb9721ed0929d0f55d167c2222d288b529723afbef0a07ed7aa6cca72380/yq-3.4.3.tar.gz", hash = "sha256:ba586a1a6f30cf705b2f92206712df2281cd320280210e7b7b80adcb8f256e3b", size = 33214, upload-time = "2024-04-27T15:39:43.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/ba/d1b21f3e57469030bd6536b91bb28fedd2511d4e68b5a575f2bdb3a3dbb6/yq-3.4.3-py3-none-any.whl", hash = "sha256:547e34bc3caacce83665fd3429bf7c85f8e8b6b9aaee3f953db1ad716ff3434d", size = 18812, upload-time = "2024-04-27T15:39:41.652Z" }, +] + +[[package]] +name = "zict" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/ac/3c494dd7ec5122cff8252c1a209b282c0867af029f805ae9befd73ae37eb/zict-3.0.0.tar.gz", hash = "sha256:e321e263b6a97aafc0790c3cfb3c04656b7066e6738c37fffcca95d803c9fba5", size = 33238, upload-time = "2023-04-17T21:41:16.041Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/ab/11a76c1e2126084fde2639514f24e6111b789b0bfa4fc6264a8975c7e1f1/zict-3.0.0-py2.py3-none-any.whl", hash = "sha256:5796e36bd0e0cc8cf0fbc1ace6a68912611c1dbd74750a3f3026b9b9d6a327ae", size = 43332, upload-time = "2023-04-17T21:41:13.444Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, +] diff --git a/uv.lock b/uv.lock index 0fb0c78fbb..5db4b9844b 100644 --- a/uv.lock +++ b/uv.lock @@ -440,6 +440,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + [[package]] name = "argon2-cffi" version = "25.1.0" @@ -1002,10 +1011,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/92/88/b8527e1b00c1811db wheels = [ { url = "https://files.pythonhosted.org/packages/ec/90/543f556fcfcfa270713eef906b6352ab048e1e557afec12925c991dc93c2/caio-0.9.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d6956d9e4a27021c8bd6c9677f3a59eb1d820cc32d0343cea7961a03b1371965", size = 36839, upload-time = "2025-12-26T15:21:40.267Z" }, { url = "https://files.pythonhosted.org/packages/51/3b/36f3e8ec38dafe8de4831decd2e44c69303d2a3892d16ceda42afed44e1b/caio-0.9.25-cp311-cp311-manylinux2010_x86_64.manylinux2014_x86_64.manylinux_2_12_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bf84bfa039f25ad91f4f52944452a5f6f405e8afab4d445450978cd6241d1478", size = 80255, upload-time = "2025-12-26T15:22:20.271Z" }, + { url = "https://files.pythonhosted.org/packages/df/ce/65e64867d928e6aff1b4f0e12dba0ef6d5bf412c240dc1df9d421ac10573/caio-0.9.25-cp311-cp311-manylinux_2_34_aarch64.whl", hash = "sha256:ae3d62587332bce600f861a8de6256b1014d6485cfd25d68c15caf1611dd1f7c", size = 80052, upload-time = "2026-03-04T22:08:20.402Z" }, + { url = "https://files.pythonhosted.org/packages/46/90/e278863c47e14ec58309aa2e38a45882fbe67b4cc29ec9bc8f65852d3e45/caio-0.9.25-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:fc220b8533dcf0f238a6b1a4a937f92024c71e7b10b5a2dfc1c73604a25709bc", size = 78273, upload-time = "2026-03-04T22:08:21.368Z" }, { url = "https://files.pythonhosted.org/packages/d3/25/79c98ebe12df31548ba4eaf44db11b7cad6b3e7b4203718335620939083c/caio-0.9.25-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fb7ff95af4c31ad3f03179149aab61097a71fd85e05f89b4786de0359dffd044", size = 36983, upload-time = "2025-12-26T15:21:36.075Z" }, { url = "https://files.pythonhosted.org/packages/a3/2b/21288691f16d479945968a0a4f2856818c1c5be56881d51d4dac9b255d26/caio-0.9.25-cp312-cp312-manylinux2010_x86_64.manylinux2014_x86_64.manylinux_2_12_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:97084e4e30dfa598449d874c4d8e0c8d5ea17d2f752ef5e48e150ff9d240cd64", size = 82012, upload-time = "2025-12-26T15:22:20.983Z" }, + { url = "https://files.pythonhosted.org/packages/03/c4/8a1b580875303500a9c12b9e0af58cb82e47f5bcf888c2457742a138273c/caio-0.9.25-cp312-cp312-manylinux_2_34_aarch64.whl", hash = "sha256:4fa69eba47e0f041b9d4f336e2ad40740681c43e686b18b191b6c5f4c5544bfb", size = 81502, upload-time = "2026-03-04T22:08:22.381Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/0fe770b8ffc8362c48134d1592d653a81a3d8748d764bec33864db36319d/caio-0.9.25-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:6bebf6f079f1341d19f7386db9b8b1f07e8cc15ae13bfdaff573371ba0575d69", size = 80200, upload-time = "2026-03-04T22:08:23.382Z" }, { url = "https://files.pythonhosted.org/packages/31/57/5e6ff127e6f62c9f15d989560435c642144aa4210882f9494204bc892305/caio-0.9.25-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d6c2a3411af97762a2b03840c3cec2f7f728921ff8adda53d7ea2315a8563451", size = 36979, upload-time = "2025-12-26T15:21:35.484Z" }, { url = "https://files.pythonhosted.org/packages/a3/9f/f21af50e72117eb528c422d4276cbac11fb941b1b812b182e0a9c70d19c5/caio-0.9.25-cp313-cp313-manylinux2010_x86_64.manylinux2014_x86_64.manylinux_2_12_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0998210a4d5cd5cb565b32ccfe4e53d67303f868a76f212e002a8554692870e6", size = 81900, upload-time = "2025-12-26T15:22:21.919Z" }, + { url = "https://files.pythonhosted.org/packages/9c/12/c39ae2a4037cb10ad5eb3578eb4d5f8c1a2575c62bba675f3406b7ef0824/caio-0.9.25-cp313-cp313-manylinux_2_34_aarch64.whl", hash = "sha256:1a177d4777141b96f175fe2c37a3d96dec7911ed9ad5f02bac38aaa1c936611f", size = 81523, upload-time = "2026-03-04T22:08:25.187Z" }, + { url = "https://files.pythonhosted.org/packages/22/59/f8f2e950eb4f1a5a3883e198dca514b9d475415cb6cd7b78b9213a0dd45a/caio-0.9.25-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:9ed3cfb28c0e99fec5e208c934e5c157d0866aa9c32aa4dc5e9b6034af6286b7", size = 80243, upload-time = "2026-03-04T22:08:26.449Z" }, { url = "https://files.pythonhosted.org/packages/86/93/1f76c8d1bafe3b0614e06b2195784a3765bbf7b0a067661af9e2dd47fc33/caio-0.9.25-py3-none-any.whl", hash = "sha256:06c0bb02d6b929119b1cfbe1ca403c768b2013a369e2db46bfa2a5761cf82e40", size = 19087, upload-time = "2025-12-26T15:22:00.221Z" }, ] @@ -1585,6 +1600,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" }, ] +[[package]] +name = "cuda-bindings" +version = "12.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-pathfinder", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/2b/ebcbb60aa6dba830474cd360c42e10282f7a343c0a1f58d24fbd3b7c2d77/cuda_bindings-12.9.4-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6a429dc6c13148ff1e27c44f40a3dd23203823e637b87fd0854205195988306", size = 11840604, upload-time = "2025-10-21T14:51:34.565Z" }, + { url = "https://files.pythonhosted.org/packages/45/e7/b47792cc2d01c7e1d37c32402182524774dadd2d26339bd224e0e913832e/cuda_bindings-12.9.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c912a3d9e6b6651853eed8eed96d6800d69c08e94052c292fec3f282c5a817c9", size = 12210593, upload-time = "2025-10-21T14:51:36.574Z" }, + { url = "https://files.pythonhosted.org/packages/dd/be/90d32049e06abcfba4b2e7df1dbcb5e16215c8852eef0cd8b25f38a66bd4/cuda_bindings-12.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:443b0875916879c2e4c3722941e25e42d5ab9bcbf34c9e83404fb100fa1f6913", size = 11490933, upload-time = "2025-10-21T14:51:38.792Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c2/65bfd79292b8ff18be4dd7f7442cea37bcbc1a228c1886f1dea515c45b67/cuda_bindings-12.9.4-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:694ba35023846625ef471257e6b5a4bc8af690f961d197d77d34b1d1db393f56", size = 11760260, upload-time = "2025-10-21T14:51:40.79Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c1/dabe88f52c3e3760d861401bb994df08f672ec893b8f7592dc91626adcf3/cuda_bindings-12.9.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fda147a344e8eaeca0c6ff113d2851ffca8f7dfc0a6c932374ee5c47caa649c8", size = 12151019, upload-time = "2025-10-21T14:51:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/df/6b/9c1b1a6c01392bfdd758e9486f52a1a72bc8f49e98f9355774ef98b5fb4e/cuda_bindings-12.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:696ca75d249ddf287d01b9a698b8e2d8a05046495a9c051ca15659dc52d17615", size = 11586961, upload-time = "2025-10-21T14:51:45.394Z" }, + { url = "https://files.pythonhosted.org/packages/05/8b/b4b2d1c7775fa403b64333e720cfcfccef8dcb9cdeb99947061ca5a77628/cuda_bindings-12.9.4-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf8bfaedc238f3b115d957d1fd6562b7e8435ba57f6d0e2f87d0e7149ccb2da5", size = 11570071, upload-time = "2025-10-21T14:51:47.472Z" }, + { url = "https://files.pythonhosted.org/packages/63/56/e465c31dc9111be3441a9ba7df1941fe98f4aa6e71e8788a3fb4534ce24d/cuda_bindings-12.9.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:32bdc5a76906be4c61eb98f546a6786c5773a881f3b166486449b5d141e4a39f", size = 11906628, upload-time = "2025-10-21T14:51:49.905Z" }, + { url = "https://files.pythonhosted.org/packages/05/d0/d0e4e2e047d8e899f023fa15ad5e9894ce951253f4c894f1cd68490fdb14/cuda_bindings-12.9.4-cp313-cp313-win_amd64.whl", hash = "sha256:a2e82c8985948f953c2be51df45c3fe11c812a928fca525154fb9503190b3e64", size = 11556719, upload-time = "2025-10-21T14:51:52.248Z" }, + { url = "https://files.pythonhosted.org/packages/ec/07/6aff13bc1e977e35aaa6b22f52b172e2890c608c6db22438cf7ed2bf43a6/cuda_bindings-12.9.4-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3adf4958dcf68ae7801a59b73fb00a8b37f8d0595060d66ceae111b1002de38d", size = 11566797, upload-time = "2025-10-21T14:51:54.581Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/1e6be415e37478070aeeee5884c2022713c1ecc735e6d82d744de0252eee/cuda_bindings-12.9.4-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56e0043c457a99ac473ddc926fe0dc4046694d99caef633e92601ab52cbe17eb", size = 11925991, upload-time = "2025-10-21T14:51:56.535Z" }, + { url = "https://files.pythonhosted.org/packages/4d/3c/972edfddb4ae8a9fccd3c3766ed47453b6f805b6026b32f10209dd4b8ad4/cuda_bindings-12.9.4-cp313-cp313t-win_amd64.whl", hash = "sha256:b32d8b685f0e66f5658bcf4601ef034e89fc2843582886f0a58784a4302da06c", size = 11894363, upload-time = "2025-10-21T14:51:58.633Z" }, +] + +[[package]] +name = "cuda-pathfinder" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/02/59a5bc738a09def0b49aea0e460bdf97f65206d0d041246147cf6207e69c/cuda_pathfinder-1.4.1-py3-none-any.whl", hash = "sha256:40793006082de88e0950753655e55558a446bed9a7d9d0bcb48b2506d50ed82a", size = 43903, upload-time = "2026-03-06T21:05:24.372Z" }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -5625,6 +5670,62 @@ requires-dist = [ { name = "usearch", specifier = "~=2.21" }, ] +[[package]] +name = "nat-benchmark-agent-leaderboard" +source = { editable = "examples/benchmarks/agent_leaderboard" } +dependencies = [ + { name = "nvidia-nat", extra = ["eval", "langchain", "test"] }, + { name = "nvidia-nat-benchmarks", extra = ["agent-leaderboard"] }, +] + +[package.metadata] +requires-dist = [ + { name = "nvidia-nat", extras = ["eval", "langchain", "test"], editable = "." }, + { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard"], editable = "packages/nvidia_nat_benchmarks" }, +] + +[[package]] +name = "nat-benchmark-bfcl" +source = { editable = "examples/benchmarks/bfcl" } +dependencies = [ + { name = "nvidia-nat", extra = ["eval", "langchain", "test"] }, + { name = "nvidia-nat-benchmarks", extra = ["bfcl"] }, +] + +[package.metadata] +requires-dist = [ + { name = "nvidia-nat", extras = ["eval", "langchain", "test"], editable = "." }, + { name = "nvidia-nat-benchmarks", extras = ["bfcl"], editable = "packages/nvidia_nat_benchmarks" }, +] + +[[package]] +name = "nat-benchmark-byob" +source = { editable = "examples/benchmarks/byob" } +dependencies = [ + { name = "nvidia-nat", extra = ["eval", "langchain", "test"] }, + { name = "nvidia-nat-benchmarks", extra = ["byob"] }, +] + +[package.metadata] +requires-dist = [ + { name = "nvidia-nat", extras = ["eval", "langchain", "test"], editable = "." }, + { name = "nvidia-nat-benchmarks", extras = ["byob"], editable = "packages/nvidia_nat_benchmarks" }, +] + +[[package]] +name = "nat-benchmark-tooltalk" +source = { editable = "examples/benchmarks/tooltalk" } +dependencies = [ + { name = "nvidia-nat", extra = ["eval", "langchain", "test"] }, + { name = "nvidia-nat-benchmarks", extra = ["tooltalk"] }, +] + +[package.metadata] +requires-dist = [ + { name = "nvidia-nat", extras = ["eval", "langchain", "test"], editable = "." }, + { name = "nvidia-nat-benchmarks", extras = ["tooltalk"], editable = "packages/nvidia_nat_benchmarks" }, +] + [[package]] name = "nat-currency-agent-a2a" source = { editable = "examples/A2A/currency_agent_a2a" } @@ -6265,6 +6366,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/78/843bcf0cf31f88d2f8a9a063d2d80817b1901657d83d65b89b3aa835732e/nbsphinx-0.9.8-py3-none-any.whl", hash = "sha256:92d95ee91784e56bc633b60b767a6b6f23a0445f891e24641ce3c3f004759ccf", size = 31961, upload-time = "2025-11-28T17:41:00.796Z" }, ] +[[package]] +name = "nemo-evaluator" +version = "0.1.95" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flask" }, + { name = "httpx" }, + { name = "jinja2" }, + { name = "psutil" }, + { name = "pydantic" }, + { name = "pydantic-core" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "structlog" }, + { name = "typing-extensions" }, + { name = "werkzeug" }, + { name = "yq" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/d7/435c316dd105567aeba3717dec50ce0fa6c74d1ad41cf2388cd394310119/nemo_evaluator-0.1.95.tar.gz", hash = "sha256:0d5c771697077587b31f6818f29b8544f0a05ea134ee8877d2d48f4007beec16", size = 150232, upload-time = "2026-03-05T01:38:01.264Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/02/493061480914ed3494cf96ae81757a96a01615d909c94c24d48ec34fef57/nemo_evaluator-0.1.95-py3-none-any.whl", hash = "sha256:22fa6f36b53b19d1faa135115e3208eebc129767846fea7da1788a0d729cb755", size = 197442, upload-time = "2026-03-05T01:37:58.331Z" }, +] + [[package]] name = "nemo-microservices" version = "1.5.0" @@ -6414,6 +6538,129 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" }, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124, upload-time = "2025-03-07T01:43:53.556Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, + { url = "https://files.pythonhosted.org/packages/70/61/7d7b3c70186fb651d0fbd35b01dbfc8e755f69fd58f817f3d0f642df20c3/nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af", size = 567544208, upload-time = "2025-03-07T01:53:30.535Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318, upload-time = "2025-03-07T01:40:10.421Z" }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, + { url = "https://files.pythonhosted.org/packages/41/bc/83f5426095d93694ae39fe1311431b5d5a9bb82e48bf0dd8e19be2765942/nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e", size = 7015759, upload-time = "2025-03-07T01:51:11.355Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076, upload-time = "2025-03-07T01:41:59.817Z" }, + { url = "https://files.pythonhosted.org/packages/45/51/52a3d84baa2136cc8df15500ad731d74d3a1114d4c123e043cb608d4a32b/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909", size = 73586838, upload-time = "2025-03-07T01:52:13.483Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265, upload-time = "2025-03-07T01:39:43.533Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, + { url = "https://files.pythonhosted.org/packages/30/a5/a515b7600ad361ea14bfa13fb4d6687abf500adc270f19e89849c0590492/nvidia_cuda_runtime_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:c0c6027f01505bfed6c3b21ec546f69c687689aad5f1a377554bc6ca4aa993a8", size = 944318, upload-time = "2025-03-07T01:51:01.794Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878, upload-time = "2025-06-06T21:52:51.348Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, + { url = "https://files.pythonhosted.org/packages/3d/90/0bd6e586701b3a890fd38aa71c387dab4883d619d6e5ad912ccbd05bfd67/nvidia_cudnn_cu12-9.10.2.21-py3-none-win_amd64.whl", hash = "sha256:c6288de7d63e6cf62988f0923f96dc339cea362decb1bf5b3141883392a7d65e", size = 692992268, upload-time = "2025-06-06T21:55:18.114Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211, upload-time = "2025-03-07T01:44:56.873Z" }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ec/ce1629f1e478bb5ccd208986b5f9e0316a78538dd6ab1d0484f012f8e2a1/nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7", size = 192216559, upload-time = "2025-03-07T01:53:57.106Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705, upload-time = "2025-03-07T01:45:41.434Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754, upload-time = "2025-03-07T01:46:10.735Z" }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, + { url = "https://files.pythonhosted.org/packages/b9/75/70c05b2f3ed5be3bb30b7102b6eb78e100da4bbf6944fd6725c012831cab/nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec", size = 62765309, upload-time = "2025-03-07T01:54:20.478Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cusparse-cu12", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841, upload-time = "2025-03-07T01:46:54.356Z" }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, + { url = "https://files.pythonhosted.org/packages/13/c0/76ca8551b8a84146ffa189fec81c26d04adba4bc0dbe09cd6e6fd9b7de04/nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34", size = 256720438, upload-time = "2025-03-07T01:54:39.898Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux' or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129, upload-time = "2025-03-07T01:47:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, + { url = "https://files.pythonhosted.org/packages/62/07/f3b2ad63f8e3d257a599f422ae34eb565e70c41031aecefa3d18b62cabd1/nvidia_cusparse_cu12-12.5.8.93-py3-none-win_amd64.whl", hash = "sha256:9a33604331cb2cac199f2e7f5104dfbb8a5a898c367a53dfda9ff2acb6b6b4dd", size = 284937404, upload-time = "2025-03-07T01:55:07.742Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557, upload-time = "2025-02-26T00:16:54.265Z" }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d8/a6b0d0d0c2435e9310f3e2bb0d9c9dd4c33daef86aa5f30b3681defd37ea/nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075", size = 271020911, upload-time = "2025-02-26T00:14:47.204Z" }, +] + [[package]] name = "nvidia-haystack" version = "0.3.0" @@ -6473,6 +6720,10 @@ examples = [ { name = "nat-alert-triage-agent" }, { name = "nat-autogen-demo" }, { name = "nat-automated-description-generation" }, + { name = "nat-benchmark-agent-leaderboard" }, + { name = "nat-benchmark-bfcl" }, + { name = "nat-benchmark-byob" }, + { name = "nat-benchmark-tooltalk" }, { name = "nat-currency-agent-a2a" }, { name = "nat-documentation-guides" }, { name = "nat-dpo-tic-tac-toe" }, @@ -6657,6 +6908,10 @@ requires-dist = [ { name = "nat-alert-triage-agent", marker = "extra == 'examples'", editable = "examples/advanced_agents/alert_triage_agent" }, { name = "nat-autogen-demo", marker = "extra == 'examples'", editable = "examples/frameworks/nat_autogen_demo" }, { name = "nat-automated-description-generation", marker = "extra == 'examples'", editable = "examples/custom_functions/automated_description_generation" }, + { name = "nat-benchmark-agent-leaderboard", marker = "extra == 'examples'", editable = "examples/benchmarks/agent_leaderboard" }, + { name = "nat-benchmark-bfcl", marker = "extra == 'examples'", editable = "examples/benchmarks/bfcl" }, + { name = "nat-benchmark-byob", marker = "extra == 'examples'", editable = "examples/benchmarks/byob" }, + { name = "nat-benchmark-tooltalk", marker = "extra == 'examples'", editable = "examples/benchmarks/tooltalk" }, { name = "nat-currency-agent-a2a", marker = "extra == 'examples'", editable = "examples/A2A/currency_agent_a2a" }, { name = "nat-documentation-guides", marker = "extra == 'examples'", editable = "examples/documentation_guides" }, { name = "nat-dpo-tic-tac-toe", marker = "extra == 'examples'", editable = "examples/finetuning/dpo_tic_tac_toe" }, @@ -6879,6 +7134,49 @@ requires-dist = [ ] provides-extras = ["test"] +[[package]] +name = "nvidia-nat-benchmarks" +source = { editable = "packages/nvidia_nat_benchmarks" } +dependencies = [ + { name = "nvidia-nat-core" }, + { name = "nvidia-nat-eval" }, + { name = "nvidia-nat-langchain" }, +] + +[package.optional-dependencies] +agent-leaderboard = [ + { name = "datasets" }, +] +bfcl = [ + { name = "tree-sitter" }, + { name = "tree-sitter-java" }, + { name = "tree-sitter-javascript" }, +] +byob = [ + { name = "nemo-evaluator" }, +] +tooltalk = [ + { name = "nvidia-tooltalk" }, +] + +[package.metadata] +requires-dist = [ + { name = "datasets", marker = "extra == 'agent-leaderboard'", specifier = "~=4.4" }, + { name = "nemo-evaluator", marker = "extra == 'byob'", specifier = "~=0.1" }, + { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard", "bfcl", "byob", "tooltalk"], marker = "extra == 'all'", specifier = "==1.6.0.dev51+gab4c3030" }, + { name = "nvidia-nat-benchmarks", extras = ["all"], marker = "extra == 'test'", specifier = "==1.6.0.dev51+gab4c3030" }, + { name = "nvidia-nat-core", editable = "packages/nvidia_nat_core" }, + { name = "nvidia-nat-core", extras = ["async-endpoints"], marker = "extra == 'test'", editable = "packages/nvidia_nat_core" }, + { name = "nvidia-nat-eval", editable = "packages/nvidia_nat_eval" }, + { name = "nvidia-nat-langchain", editable = "packages/nvidia_nat_langchain" }, + { name = "nvidia-nat-test", marker = "extra == 'test'", editable = "packages/nvidia_nat_test" }, + { name = "nvidia-tooltalk", marker = "extra == 'tooltalk'", specifier = "~=26.1" }, + { name = "tree-sitter", marker = "extra == 'bfcl'", specifier = "~=0.21.0" }, + { name = "tree-sitter-java", marker = "extra == 'bfcl'", specifier = "~=0.21.0" }, + { name = "tree-sitter-javascript", marker = "extra == 'bfcl'", specifier = "~=0.21.0" }, +] +provides-extras = ["tooltalk", "bfcl", "byob", "agent-leaderboard", "all", "test"] + [[package]] name = "nvidia-nat-core" source = { editable = "packages/nvidia_nat_core" } @@ -7533,6 +7831,44 @@ requires-dist = [ ] provides-extras = ["test"] +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625, upload-time = "2025-06-26T04:11:04.496Z" }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204, upload-time = "2025-03-07T01:49:43.612Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d7/34f02dad2e30c31b10a51f6b04e025e5dd60e5f936af9045a9b858a05383/nvidia_nvjitlink_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:bd93fbeeee850917903583587f4fc3a4eafa022e34572251368238ab5e6bd67f", size = 268553710, upload-time = "2025-03-07T01:56:24.13Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/6a/03aa43cc9bd3ad91553a88b5f6fb25ed6a3752ae86ce2180221962bc2aa5/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b48363fc6964dede448029434c6abed6c5e37f823cb43c3bcde7ecfc0457e15", size = 138936938, upload-time = "2025-09-06T00:32:05.589Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161, upload-time = "2025-03-07T01:42:23.922Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/9f/99/4c9c0c329bf9fc125008c3b54c7c94c0023518d06fc025ae36431375e1fe/nvidia_nvtx_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:619c8304aedc69f02ea82dd244541a83c3d9d40993381b3b590f1adaed3db41e", size = 56492, upload-time = "2025-03-07T01:52:24.69Z" }, +] + [[package]] name = "nvidia-rag" version = "2.4.0" @@ -7578,6 +7914,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8c/79/017fab2f7167a9a9795665f894d04f77aafceca80821b51589bb4b23ff5c/nvidia_sphinx_theme-0.0.9.post1-py3-none-any.whl", hash = "sha256:21ca60206dff2f380d7783d64bbaf71a5b9cacae53c7d0686f089c16b5a3d45a", size = 143816, upload-time = "2025-11-09T23:16:55.719Z" }, ] +[[package]] +name = "nvidia-tooltalk" +version = "26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "nemo-evaluator" }, + { name = "numpy" }, + { name = "openai" }, + { name = "pytest" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/81/5cef75e53bddb8f1df42c3b25390cb3a8fcf75569047248cb02bb9721e33/nvidia_tooltalk-26.1-py3-none-any.whl", hash = "sha256:a6bfedbb590e50a55cbcf14bfe430d16e18c020998e0fbb6c8700685bb2442b7", size = 165640, upload-time = "2026-02-27T08:28:30.982Z" }, +] + [[package]] name = "oauthlib" version = "3.3.1" @@ -11502,6 +11856,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/cf/0fea4f4ba3fc2772ac2419278aa9f6964124d4302117d61bc055758e000c/striprtf-0.0.26-py3-none-any.whl", hash = "sha256:8c8f9d32083cdc2e8bfb149455aa1cc5a4e0a035893bedc75db8b73becb3a1bb", size = 6914, upload-time = "2023-07-20T14:30:35.338Z" }, ] +[[package]] +name = "structlog" +version = "25.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/52/9ba0f43b686e7f3ddfeaa78ac3af750292662284b3661e91ad5494f21dbc/structlog-25.5.0.tar.gz", hash = "sha256:098522a3bebed9153d4570c6d0288abf80a031dfdb2048d59a49e9dc2190fc98", size = 1460830, upload-time = "2025-10-27T08:28:23.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl", hash = "sha256:a8453e9b9e636ec59bd9e79bbd4a72f025981b3ba0f5837aebf48f02f37a7f9f", size = 72510, upload-time = "2025-10-27T08:28:21.535Z" }, +] + [[package]] name = "sympy" version = "1.14.0" @@ -11803,6 +12166,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, ] +[[package]] +name = "tomlkit" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" }, +] + [[package]] name = "toolz" version = "1.1.0" @@ -11812,6 +12184,59 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093, upload-time = "2025-10-17T04:03:20.435Z" }, ] +[[package]] +name = "torch" +version = "2.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-bindings", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cuda-cupti-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cuda-runtime-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cudnn-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cufft-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cufile-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-curand-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cusolver-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-cusparselt-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-nccl-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-nvshmem-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "nvidia-nvtx-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "setuptools", version = "81.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai')" }, + { name = "setuptools", version = "82.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and extra == 'extra-10-nvidia-nat-adk') or (python_full_version >= '3.12' and extra == 'extra-10-nvidia-nat-most') or (python_full_version >= '3.12' and extra != 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "sympy" }, + { name = "triton", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (platform_machine != 'x86_64' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-adk' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-autogen' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-crewai' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-openpipe-art') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-rag') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-most' and extra == 'extra-10-nvidia-nat-ragaai') or (sys_platform != 'linux' and extra == 'extra-10-nvidia-nat-ragaai' and extra == 'extra-10-nvidia-nat-strands')" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/8b/4b61d6e13f7108f36910df9ab4b58fd389cc2520d54d81b88660804aad99/torch-2.10.0-2-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:418997cb02d0a0f1497cf6a09f63166f9f5df9f3e16c8a716ab76a72127c714f", size = 79423467, upload-time = "2026-02-10T21:44:48.711Z" }, + { url = "https://files.pythonhosted.org/packages/d3/54/a2ba279afcca44bbd320d4e73675b282fcee3d81400ea1b53934efca6462/torch-2.10.0-2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:13ec4add8c3faaed8d13e0574f5cd4a323c11655546f91fbe6afa77b57423574", size = 79498202, upload-time = "2026-02-10T21:44:52.603Z" }, + { url = "https://files.pythonhosted.org/packages/ec/23/2c9fe0c9c27f7f6cb865abcea8a4568f29f00acaeadfc6a37f6801f84cb4/torch-2.10.0-2-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:e521c9f030a3774ed770a9c011751fb47c4d12029a3d6522116e48431f2ff89e", size = 79498254, upload-time = "2026-02-10T21:44:44.095Z" }, + { url = "https://files.pythonhosted.org/packages/78/89/f5554b13ebd71e05c0b002f95148033e730d3f7067f67423026cc9c69410/torch-2.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3282d9febd1e4e476630a099692b44fdc214ee9bf8ee5377732d9d9dfe5712e4", size = 145992610, upload-time = "2026-01-21T16:25:26.327Z" }, + { url = "https://files.pythonhosted.org/packages/ae/30/a3a2120621bf9c17779b169fc17e3dc29b230c29d0f8222f499f5e159aa8/torch-2.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a2f9edd8dbc99f62bc4dfb78af7bf89499bca3d753423ac1b4e06592e467b763", size = 915607863, upload-time = "2026-01-21T16:25:06.696Z" }, + { url = "https://files.pythonhosted.org/packages/6f/3d/c87b33c5f260a2a8ad68da7147e105f05868c281c63d65ed85aa4da98c66/torch-2.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:29b7009dba4b7a1c960260fc8ac85022c784250af43af9fb0ebafc9883782ebd", size = 113723116, upload-time = "2026-01-21T16:25:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/61/d8/15b9d9d3a6b0c01b883787bd056acbe5cc321090d4b216d3ea89a8fcfdf3/torch-2.10.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:b7bd80f3477b830dd166c707c5b0b82a898e7b16f59a7d9d42778dd058272e8b", size = 79423461, upload-time = "2026-01-21T16:24:50.266Z" }, + { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" }, + { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" }, + { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5c/dee910b87c4d5c0fcb41b50839ae04df87c1cfc663cf1b5fca7ea565eeaa/torch-2.10.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:6d3707a61863d1c4d6ebba7be4ca320f42b869ee657e9b2c21c736bf17000294", size = 79498198, upload-time = "2026-01-21T16:24:34.704Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6f/f2e91e34e3fcba2e3fc8d8f74e7d6c22e74e480bbd1db7bc8900fdf3e95c/torch-2.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5c4d217b14741e40776dd7074d9006fd28b8a97ef5654db959d8635b2fe5f29b", size = 146004247, upload-time = "2026-01-21T16:24:29.335Z" }, + { url = "https://files.pythonhosted.org/packages/98/fb/5160261aeb5e1ee12ee95fe599d0541f7c976c3701d607d8fc29e623229f/torch-2.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6b71486353fce0f9714ca0c9ef1c850a2ae766b409808acd58e9678a3edb7738", size = 915716445, upload-time = "2026-01-21T16:22:45.353Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/502fb1b41e6d868e8deb5b0e3ae926bbb36dab8ceb0d1b769b266ad7b0c3/torch-2.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2ee399c644dc92ef7bc0d4f7e74b5360c37cdbe7c5ba11318dda49ffac2bc57", size = 113757050, upload-time = "2026-01-21T16:24:19.204Z" }, + { url = "https://files.pythonhosted.org/packages/1a/0b/39929b148f4824bc3ad6f9f72a29d4ad865bcf7ebfc2fa67584773e083d2/torch-2.10.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:3202429f58309b9fa96a614885eace4b7995729f44beb54d3e4a47773649d382", size = 79851305, upload-time = "2026-01-21T16:24:09.209Z" }, + { url = "https://files.pythonhosted.org/packages/d8/14/21fbce63bc452381ba5f74a2c0a959fdf5ad5803ccc0c654e752e0dbe91a/torch-2.10.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:aae1b29cd68e50a9397f5ee897b9c24742e9e306f88a807a27d617f07adb3bd8", size = 146005472, upload-time = "2026-01-21T16:22:29.022Z" }, + { url = "https://files.pythonhosted.org/packages/54/fd/b207d1c525cb570ef47f3e9f836b154685011fce11a2f444ba8a4084d042/torch-2.10.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6021db85958db2f07ec94e1bc77212721ba4920c12a18dc552d2ae36a3eb163f", size = 915612644, upload-time = "2026-01-21T16:21:47.019Z" }, + { url = "https://files.pythonhosted.org/packages/36/53/0197f868c75f1050b199fe58f9bf3bf3aecac9b4e85cc9c964383d745403/torch-2.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff43db38af76fda183156153983c9a096fc4c78d0cd1e07b14a2314c7f01c2c8", size = 113997015, upload-time = "2026-01-21T16:23:00.767Z" }, + { url = "https://files.pythonhosted.org/packages/0e/13/e76b4d9c160e89fff48bf16b449ea324bda84745d2ab30294c37c2434c0d/torch-2.10.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:cdf2a523d699b70d613243211ecaac14fe9c5df8a0b0a9c02add60fb2a413e0f", size = 79498248, upload-time = "2026-01-21T16:23:09.315Z" }, +] + [[package]] name = "tornado" version = "6.5.4" @@ -11891,6 +12316,72 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" }, ] +[[package]] +name = "tree-sitter" +version = "0.21.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/39/9e/b7cb190aa08e4ea387f2b1531da03efb4b8b033426753c0b97e3698645f6/tree-sitter-0.21.3.tar.gz", hash = "sha256:b5de3028921522365aa864d95b3c41926e0ba6a85ee5bd000e10dc49b0766988", size = 155688, upload-time = "2024-03-26T10:53:35.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/b5/72657d5874d7f0a722c0288f04e5e2bc33d7715b13a858885b6593047dce/tree_sitter-0.21.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54b22c3c2aab3e3639a4b255d9df8455da2921d050c4829b6a5663b057f10db5", size = 133429, upload-time = "2024-03-26T10:52:46.345Z" }, + { url = "https://files.pythonhosted.org/packages/d3/64/c5d397efbb6d0dbed4254cd2ca389ed186a2e1e7e32661059f6eeaaf6424/tree_sitter-0.21.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab6e88c1e2d5e84ff0f9e5cd83f21b8e5074ad292a2cf19df3ba31d94fbcecd4", size = 126088, upload-time = "2024-03-26T10:52:47.759Z" }, + { url = "https://files.pythonhosted.org/packages/ba/88/941669acc140f94e6c6196d6d8676ac4cd57c3b3fbc1ee61bb11c1b2da71/tree_sitter-0.21.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3fd34ed4cd5db445bc448361b5da46a2a781c648328dc5879d768f16a46771", size = 487879, upload-time = "2024-03-26T10:52:49.091Z" }, + { url = "https://files.pythonhosted.org/packages/29/4e/798154f2846d620bf9fa3bc244e056d4858f2108f834656bf9f1219d4f30/tree_sitter-0.21.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fabc7182f6083269ce3cfcad202fe01516aa80df64573b390af6cd853e8444a1", size = 498776, upload-time = "2024-03-26T10:52:50.709Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d1/05ea77487bc7a3946d0e80fb6c5cb61515953f5e7a4f6804b98e113ed4b0/tree_sitter-0.21.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f874c3f7d2a2faf5c91982dc7d88ff2a8f183a21fe475c29bee3009773b0558", size = 483348, upload-time = "2024-03-26T10:52:52.267Z" }, + { url = "https://files.pythonhosted.org/packages/42/fa/bf938e7c6afbc368d503deeda060891c3dba57e2d1166e4b884271f55616/tree_sitter-0.21.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ee61ee3b7a4eedf9d8f1635c68ba4a6fa8c46929601fc48a907c6cfef0cfbcb2", size = 493757, upload-time = "2024-03-26T10:52:54.845Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a7/98da36a6eab22f5729989c9e0137b1b04cbe368d1e024fccd72c0b00719b/tree_sitter-0.21.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b7256c723642de1c05fbb776b27742204a2382e337af22f4d9e279d77df7aa2", size = 109735, upload-time = "2024-03-26T10:52:57.243Z" }, + { url = "https://files.pythonhosted.org/packages/81/e1/cceb06eae617a6bf5eeeefa9813d9fd57d89b50f526ce02486a336bcd2a9/tree_sitter-0.21.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:669b3e5a52cb1e37d60c7b16cc2221c76520445bb4f12dd17fd7220217f5abf3", size = 133640, upload-time = "2024-03-26T10:52:59.135Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ce/ac14e5cbb0f30b7bd338122491ee2b8e6c0408cfe26741cbd66fa9b53d35/tree_sitter-0.21.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2aa2a5099a9f667730ff26d57533cc893d766667f4d8a9877e76a9e74f48f0d3", size = 125954, upload-time = "2024-03-26T10:53:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/c2/df/76dbf830126e566c48db0d1bf2bef3f9d8cac938302a9b0f762ded8206c2/tree_sitter-0.21.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3e06ae2a517cf6f1abb682974f76fa760298e6d5a3ecf2cf140c70f898adf0", size = 490092, upload-time = "2024-03-26T10:53:03.144Z" }, + { url = "https://files.pythonhosted.org/packages/ec/87/0c3593552cb0d09ab6271d37fc0e6a9476919d2a975661d709d4b3289fc7/tree_sitter-0.21.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af992dfe08b4fefcfcdb40548d0d26d5d2e0a0f2d833487372f3728cd0772b48", size = 502155, upload-time = "2024-03-26T10:53:04.76Z" }, + { url = "https://files.pythonhosted.org/packages/05/92/b2cb22cf52c18fcc95662897f380cf230c443dfc9196b872aad5948b7bb3/tree_sitter-0.21.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c7cbab1dd9765138505c4a55e2aa857575bac4f1f8a8b0457744a4fefa1288e6", size = 486020, upload-time = "2024-03-26T10:53:06.414Z" }, + { url = "https://files.pythonhosted.org/packages/4a/ea/69b543538a46d763f3e787234d1617b718ab90f32ffa676ca856f1d9540e/tree_sitter-0.21.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1e66aeb457d1529370fcb0997ae5584c6879e0e662f1b11b2f295ea57e22f54", size = 496348, upload-time = "2024-03-26T10:53:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/eb/4f/df4ea84476443021707b537217c32147ccccbc3e10c17b216a969991e1b3/tree_sitter-0.21.3-cp312-cp312-win_amd64.whl", hash = "sha256:013c750252dc3bd0e069d82e9658de35ed50eecf31c6586d0de7f942546824c5", size = 109771, upload-time = "2024-03-26T10:53:10.342Z" }, +] + +[[package]] +name = "tree-sitter-java" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/33/627a1bc82178131057bfad7ba1178f09979ac6ee8034915eb3caf0ff6088/tree_sitter_java-0.21.0-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d30fb39af6590f6be877ff8d39c7e193f37594375b8fcdda55babd264411616b", size = 75795, upload-time = "2024-04-07T18:43:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/4e/5a/c274c4b338b77035804905d216c73dbf7e672d5b8ef55e89ec47fa62f27a/tree_sitter_java-0.21.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:696391968cdc467f97e525fbe43790c2d5ba46bf446376eb30d5c20b5c9d795a", size = 78061, upload-time = "2024-04-07T18:43:57.438Z" }, + { url = "https://files.pythonhosted.org/packages/90/27/1fb08e41074ee0cf26741f852ab995878974f63c5ce32df929507683417b/tree_sitter_java-0.21.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b82318982531a473c598601d73956b0b1f9e608d39e427ba8c1a59f2d6da262", size = 125576, upload-time = "2024-04-07T18:43:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/60/e7/b7dee7289ff66af83bf4c784847c9ded95276794d8d070495ca4b41d963d/tree_sitter_java-0.21.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9c01f48ec3a3d4b55fb2c56b7cad6ebf94dba568d690b45d966731859485dd4", size = 116990, upload-time = "2024-04-07T18:44:00.859Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e3/591d561cc52a7b672b3c0836696b97222673ee7b0d2785b5ee26064dce1f/tree_sitter_java-0.21.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d83ca51b26826550051c53468ec74f5b570b4afb4d4520df0aa2a35b52de2289", size = 128126, upload-time = "2024-04-07T18:44:02.731Z" }, + { url = "https://files.pythonhosted.org/packages/eb/48/fbf338a749bd6e7e58bf9c30de5d7afb697a8ac5263cb68e79bdf18a6cfa/tree_sitter_java-0.21.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:8afb56c90048272b079235b82fc2a4a69b058b4ace206d9475cbad2eb143f40a", size = 119512, upload-time = "2024-04-07T18:44:04.682Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e2/a84f1b286197645cbedd360971ed0da4ad1ff21be236d927e62b679186de/tree_sitter_java-0.21.0-cp38-abi3-win_amd64.whl", hash = "sha256:6534fac27a93160a2b27a0c77f22a7c91f0aee2dba9d4cdbf835bf509ddfbf4f", size = 74376, upload-time = "2024-04-07T18:44:06.002Z" }, +] + +[[package]] +name = "tree-sitter-javascript" +version = "0.21.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/f3/16e8566c46fe14965386284296e2f83f0e06b16a613d1d518b434844180b/tree-sitter-javascript-0.21.4.tar.gz", hash = "sha256:5ae97db218c22f16f1fd1108d77c4017b453addc36041136779c99800f23ff20", size = 109366, upload-time = "2024-07-06T00:52:05.796Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/44/c677dd586079a27b5237786e14713fdbff9fc556cea968658e09e26fa472/tree_sitter_javascript-0.21.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e0f1d26ec85cc66d56fb25fd41ce499dc5c4a60b478a91754684e2289433daae", size = 57025, upload-time = "2024-07-06T00:51:56.957Z" }, + { url = "https://files.pythonhosted.org/packages/ef/49/a1dd762cfe11dbaabdcf5abb46dcf8650d89e456466cc569164bdc921d11/tree_sitter_javascript-0.21.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:e9172dc9e59649d7598c6509103db1648e7187c2bcb39c34222fc052b9db0ac4", size = 60305, upload-time = "2024-07-06T00:51:58.367Z" }, + { url = "https://files.pythonhosted.org/packages/f5/eb/1f7eb01fb0b62270c75eab9ac883a65226acfc63e76973cb21abee0ccad0/tree_sitter_javascript-0.21.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d45bd39ce931b164f84cfb6a186df504e38c6f91f541e2e60d5a40eb9d574005", size = 85520, upload-time = "2024-07-06T00:51:59.887Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e3/a9f64c23cd37e88aae0758f31502f57613aa73058fb49c1c6eb9df97d201/tree_sitter_javascript-0.21.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00ff426e9bb552abb49ce3234b083edb1a6aa73bfeea7d9bf0f6bb3d0256c4cd", size = 76624, upload-time = "2024-07-06T00:52:01.315Z" }, + { url = "https://files.pythonhosted.org/packages/61/d4/8ed6ef32244dbb652a0e433a6f357afaf91614f69159abb03e4a5f96109a/tree_sitter_javascript-0.21.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c2945bc49985ab396773e2738ae9b1e7d06950d6ad70c535c010fb9b2816a855", size = 73782, upload-time = "2024-07-06T00:52:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a1/57579a8ab9a23ea6204d54958516a0119e168960e1d34cff036b9e762abc/tree_sitter_javascript-0.21.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fc87d07f4c6a7067d4e0f004956a549c05e21eeced3287f3ea2bdd04a71a97a", size = 73276, upload-time = "2024-07-06T00:52:03.794Z" }, + { url = "https://files.pythonhosted.org/packages/19/e5/0681f027261093609cc56e5ca5e3c8e7eeee16e01081e0eee6c8d02fd2ce/tree_sitter_javascript-0.21.4-cp38-abi3-win_amd64.whl", hash = "sha256:2843b0e81564d8176922ef2b40db128a4de026606d6b1d22a06efb8e8a5c01b8", size = 60417, upload-time = "2024-07-06T00:52:04.7Z" }, +] + +[[package]] +name = "triton" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/2c/96f92f3c60387e14cc45aed49487f3486f89ea27106c1b1376913c62abe4/triton-3.6.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49df5ef37379c0c2b5c0012286f80174fcf0e073e5ade1ca9a86c36814553651", size = 176081190, upload-time = "2026-01-20T16:16:00.523Z" }, + { url = "https://files.pythonhosted.org/packages/e0/12/b05ba554d2c623bffa59922b94b0775673de251f468a9609bc9e45de95e9/triton-3.6.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8e323d608e3a9bfcc2d9efcc90ceefb764a82b99dea12a86d643c72539ad5d3", size = 188214640, upload-time = "2026-01-20T16:00:35.869Z" }, + { url = "https://files.pythonhosted.org/packages/17/5d/08201db32823bdf77a0e2b9039540080b2e5c23a20706ddba942924ebcd6/triton-3.6.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:374f52c11a711fd062b4bfbb201fd9ac0a5febd28a96fb41b4a0f51dde3157f4", size = 176128243, upload-time = "2026-01-20T16:16:07.857Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a8/cdf8b3e4c98132f965f88c2313a4b493266832ad47fb52f23d14d4f86bb5/triton-3.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74caf5e34b66d9f3a429af689c1c7128daba1d8208df60e81106b115c00d6fca", size = 188266850, upload-time = "2026-01-20T16:00:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/3c/12/34d71b350e89a204c2c7777a9bba0dcf2f19a5bfdd70b57c4dbc5ffd7154/triton-3.6.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448e02fe6dc898e9e5aa89cf0ee5c371e99df5aa5e8ad976a80b93334f3494fd", size = 176133521, upload-time = "2026-01-20T16:16:13.321Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0b/37d991d8c130ce81a8728ae3c25b6e60935838e9be1b58791f5997b24a54/triton-3.6.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9", size = 188289450, upload-time = "2026-01-20T16:00:49.136Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4e/41b0c8033b503fd3cfcd12392cdd256945026a91ff02452bef40ec34bee7/triton-3.6.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1722e172d34e32abc3eb7711d0025bb69d7959ebea84e3b7f7a341cd7ed694d6", size = 176276087, upload-time = "2026-01-20T16:16:18.989Z" }, + { url = "https://files.pythonhosted.org/packages/35/f8/9c66bfc55361ec6d0e4040a0337fb5924ceb23de4648b8a81ae9d33b2b38/triton-3.6.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f", size = 188400296, upload-time = "2026-01-20T16:00:56.042Z" }, +] + [[package]] name = "twine" version = "6.2.0" @@ -12520,6 +13011,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, ] +[[package]] +name = "xmltodict" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" }, +] + [[package]] name = "xxhash" version = "3.6.0" @@ -12683,6 +13183,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] +[[package]] +name = "yq" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "pyyaml" }, + { name = "tomlkit" }, + { name = "xmltodict" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/6a/eb9721ed0929d0f55d167c2222d288b529723afbef0a07ed7aa6cca72380/yq-3.4.3.tar.gz", hash = "sha256:ba586a1a6f30cf705b2f92206712df2281cd320280210e7b7b80adcb8f256e3b", size = 33214, upload-time = "2024-04-27T15:39:43.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/ba/d1b21f3e57469030bd6536b91bb28fedd2511d4e68b5a575f2bdb3a3dbb6/yq-3.4.3-py3-none-any.whl", hash = "sha256:547e34bc3caacce83665fd3429bf7c85f8e8b6b9aaee3f953db1ad716ff3434d", size = 18812, upload-time = "2024-04-27T15:39:41.652Z" }, +] + [[package]] name = "zep-cloud" version = "3.16.0" From 2787feab6a96fea3c1d0fca581e2f2ae1a8bd266 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 21:27:49 -0700 Subject: [PATCH 08/10] remove redundant config files Signed-off-by: Bryan Bednarski --- .../configs/agent_leaderboard_eval.yaml | 61 ------------------- .../configs/bfcl_ast_eval.yaml | 54 ---------------- .../configs/tooltalk_eval.yaml | 57 ----------------- 3 files changed, 172 deletions(-) delete mode 100644 packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml delete mode 100644 packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml delete mode 100644 packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml diff --git a/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml b/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml deleted file mode 100644 index b8161ee392..0000000000 --- a/packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Agent Leaderboard v2 evaluation config for NAT -# Usage: nat eval --config_file packages/nvidia_nat_benchmarks/configs/agent_leaderboard_eval.yaml -# -# Prerequisite: Download dataset first: -# python examples/dynamo_integration/scripts/download_agent_leaderboard_v2.py \ -# --output-dir data/agent_leaderboard --domains banking healthcare insurance investment telecom -# -# Required env vars: -# NVIDIA_API_KEY — API key for NVIDIA NIM endpoint -# AGENT_LEADERBOARD_DATA — path to downloaded JSON file (or will download from HuggingFace) - -llms: - nim_llm: - _type: nim - model_name: meta/llama-3.3-70b-instruct - base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} - api_key: ${NVIDIA_API_KEY} - max_tokens: 1024 - temperature: 0.0 - -workflow: - _type: agent_leaderboard_workflow - llm_name: nim_llm - max_steps: 10 - -eval: - general: - output_dir: .tmp/nat/benchmarks/agent_leaderboard/output/ - workflow_alias: agent_leaderboard_llama33_70b - per_input_user_id: false - max_concurrency: 5 - dataset: - _type: agent_leaderboard - file_path: ${AGENT_LEADERBOARD_DATA:-./data/agent_leaderboard/agent_leaderboard_v2_banking.json} - domains: - - banking - structure: - question_key: question - answer_key: answer - disable: true - - evaluators: - tsq: - _type: agent_leaderboard_tsq - tool_weight: 1.0 - parameter_weight: 0.0 diff --git a/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml b/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml deleted file mode 100644 index 8623a5c620..0000000000 --- a/packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# BFCL v3 AST prompting evaluation config for NAT -# Usage: nat eval --config_file packages/nvidia_nat_benchmarks/configs/bfcl_ast_eval.yaml -# -# Required env vars: -# NVIDIA_API_KEY — API key for NVIDIA NIM endpoint -# BFCL_DATASET_FILE — path to BFCL v3 test JSONL (e.g. .../bfcl/data/BFCL_v3_simple.json) - -llms: - nim_llm: - _type: nim - model_name: meta/llama-3.3-70b-instruct - base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} - api_key: ${NVIDIA_API_KEY} - max_tokens: 512 - temperature: 0.0 - -workflow: - _type: bfcl_ast_workflow - llm_name: nim_llm - -eval: - general: - output_dir: .tmp/nat/benchmarks/bfcl_ast/output/ - workflow_alias: bfcl_ast_llama33_70b - per_input_user_id: false - max_concurrency: 5 - dataset: - _type: bfcl - file_path: ${BFCL_DATASET_FILE} - test_category: simple - structure: - question_key: question - answer_key: answer - - evaluators: - bfcl: - _type: bfcl_evaluator - test_category: simple - language: Python diff --git a/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml b/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml deleted file mode 100644 index 0284b7e3c0..0000000000 --- a/packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# ToolTalk benchmark evaluation config for NAT -# Usage: nat eval --config-file packages/nvidia_nat_benchmarks/configs/tooltalk_eval.yaml -# -# Required env vars (can be set in .env): -# NVIDIA_API_KEY — API key for NVIDIA NIM endpoint -# TOOLTALK_DATABASE_DIR — path to ToolTalk database dir (e.g. .venv/.../tooltalk/data/databases) -# TOOLTALK_DATASET_DIR — path to ToolTalk dataset dir (e.g. .venv/.../tooltalk/data/easy) - -llms: - nim_llm: - _type: nim - model_name: meta/llama-3.3-70b-instruct - base_url: ${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1} - api_key: ${NVIDIA_API_KEY} - max_tokens: 1024 - temperature: 0.0 - -workflow: - _type: tooltalk_workflow - llm_name: nim_llm - database_dir: ${TOOLTALK_DATABASE_DIR} - api_mode: all - disable_documentation: false - -eval: - general: - output_dir: .tmp/nat/benchmarks/tooltalk/output/ - workflow_alias: tooltalk_llama33_70b - per_input_user_id: true - max_concurrency: 3 - dataset: - _type: tooltalk - file_path: ${TOOLTALK_DATASET_DIR} - database_dir: ${TOOLTALK_DATABASE_DIR} - structure: - question_key: question - answer_key: answer - - evaluators: - tooltalk: - _type: tooltalk_evaluator - database_dir: ${TOOLTALK_DATABASE_DIR} From 7be163e675df4cd8a58fe9cb43c622570a57ddf3 Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 22:22:22 -0700 Subject: [PATCH 09/10] remove redundant __init__.py and register.py files Signed-off-by: Bryan Bednarski --- .../benchmarks/agent_leaderboard/pyproject.toml | 2 -- .../nat_benchmark_agent_leaderboard/__init__.py | 16 ---------------- .../nat_benchmark_agent_leaderboard/register.py | 17 ----------------- examples/benchmarks/bfcl/pyproject.toml | 2 -- .../bfcl/src/nat_benchmark_bfcl/__init__.py | 16 ---------------- .../bfcl/src/nat_benchmark_bfcl/register.py | 17 ----------------- examples/benchmarks/byob/pyproject.toml | 2 -- .../byob/src/nat_benchmark_byob/__init__.py | 16 ---------------- .../byob/src/nat_benchmark_byob/register.py | 17 ----------------- examples/benchmarks/tooltalk/pyproject.toml | 2 -- .../src/nat_benchmark_tooltalk/__init__.py | 16 ---------------- .../src/nat_benchmark_tooltalk/register.py | 17 ----------------- packages/nvidia_nat_benchmarks/uv.lock | 4 ++-- uv.lock | 4 ++-- 14 files changed, 4 insertions(+), 144 deletions(-) delete mode 100644 examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py delete mode 100644 examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py delete mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py delete mode 100644 examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py delete mode 100644 examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py delete mode 100644 examples/benchmarks/byob/src/nat_benchmark_byob/register.py delete mode 100644 examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py delete mode 100644 examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py diff --git a/examples/benchmarks/agent_leaderboard/pyproject.toml b/examples/benchmarks/agent_leaderboard/pyproject.toml index 739407b612..cd77fa859a 100644 --- a/examples/benchmarks/agent_leaderboard/pyproject.toml +++ b/examples/benchmarks/agent_leaderboard/pyproject.toml @@ -41,5 +41,3 @@ dependencies = [ nvidia-nat = { path = "../../..", editable = true } nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } -[project.entry-points.'nat.components'] -nat_benchmark_agent_leaderboard = "nat_benchmark_agent_leaderboard.register" diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py deleted file mode 100644 index 0ac2afc2c1..0000000000 --- a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -from . import register # noqa: F401 diff --git a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py b/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py deleted file mode 100644 index 62316d4594..0000000000 --- a/examples/benchmarks/agent_leaderboard/src/nat_benchmark_agent_leaderboard/register.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Components are registered via nvidia-nat-benchmarks package entry points. -# This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/bfcl/pyproject.toml b/examples/benchmarks/bfcl/pyproject.toml index 605d0814ea..3b04ad2a0e 100644 --- a/examples/benchmarks/bfcl/pyproject.toml +++ b/examples/benchmarks/bfcl/pyproject.toml @@ -41,5 +41,3 @@ dependencies = [ nvidia-nat = { path = "../../..", editable = true } nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } -[project.entry-points.'nat.components'] -nat_benchmark_bfcl = "nat_benchmark_bfcl.register" diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py deleted file mode 100644 index 0ac2afc2c1..0000000000 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -from . import register # noqa: F401 diff --git a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py b/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py deleted file mode 100644 index 62316d4594..0000000000 --- a/examples/benchmarks/bfcl/src/nat_benchmark_bfcl/register.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Components are registered via nvidia-nat-benchmarks package entry points. -# This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/byob/pyproject.toml b/examples/benchmarks/byob/pyproject.toml index fdf804690a..7b937154bb 100644 --- a/examples/benchmarks/byob/pyproject.toml +++ b/examples/benchmarks/byob/pyproject.toml @@ -41,5 +41,3 @@ dependencies = [ nvidia-nat = { path = "../../..", editable = true } nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } -[project.entry-points.'nat.components'] -nat_benchmark_byob = "nat_benchmark_byob.register" diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py b/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py deleted file mode 100644 index 0ac2afc2c1..0000000000 --- a/examples/benchmarks/byob/src/nat_benchmark_byob/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -from . import register # noqa: F401 diff --git a/examples/benchmarks/byob/src/nat_benchmark_byob/register.py b/examples/benchmarks/byob/src/nat_benchmark_byob/register.py deleted file mode 100644 index 62316d4594..0000000000 --- a/examples/benchmarks/byob/src/nat_benchmark_byob/register.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Components are registered via nvidia-nat-benchmarks package entry points. -# This register.py exists for the example package structure convention. diff --git a/examples/benchmarks/tooltalk/pyproject.toml b/examples/benchmarks/tooltalk/pyproject.toml index 8c73b08314..b8abf38d4a 100644 --- a/examples/benchmarks/tooltalk/pyproject.toml +++ b/examples/benchmarks/tooltalk/pyproject.toml @@ -41,5 +41,3 @@ dependencies = [ nvidia-nat = { path = "../../..", editable = true } nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } -[project.entry-points.'nat.components'] -nat_benchmark_tooltalk = "nat_benchmark_tooltalk.register" diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py deleted file mode 100644 index 0ac2afc2c1..0000000000 --- a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -from . import register # noqa: F401 diff --git a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py b/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py deleted file mode 100644 index 62316d4594..0000000000 --- a/examples/benchmarks/tooltalk/src/nat_benchmark_tooltalk/register.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Components are registered via nvidia-nat-benchmarks package entry points. -# This register.py exists for the example package structure convention. diff --git a/packages/nvidia_nat_benchmarks/uv.lock b/packages/nvidia_nat_benchmarks/uv.lock index e14188f88d..299017c1d6 100644 --- a/packages/nvidia_nat_benchmarks/uv.lock +++ b/packages/nvidia_nat_benchmarks/uv.lock @@ -2309,8 +2309,8 @@ tooltalk = [ requires-dist = [ { name = "datasets", marker = "extra == 'agent-leaderboard'", specifier = "~=4.4" }, { name = "nemo-evaluator", marker = "extra == 'byob'", specifier = "~=0.1" }, - { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard", "bfcl", "byob", "tooltalk"], marker = "extra == 'all'", specifier = "==1.6.0.dev51+gab4c3030" }, - { name = "nvidia-nat-benchmarks", extras = ["all"], marker = "extra == 'test'", specifier = "==1.6.0.dev51+gab4c3030" }, + { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard", "bfcl", "byob", "tooltalk"], marker = "extra == 'all'", specifier = "==1.6.0.dev52+g385376c7" }, + { name = "nvidia-nat-benchmarks", extras = ["all"], marker = "extra == 'test'", specifier = "==1.6.0.dev52+g385376c7" }, { name = "nvidia-nat-core", editable = "../nvidia_nat_core" }, { name = "nvidia-nat-core", extras = ["async-endpoints"], marker = "extra == 'test'", editable = "../nvidia_nat_core" }, { name = "nvidia-nat-eval", editable = "../nvidia_nat_eval" }, diff --git a/uv.lock b/uv.lock index 5db4b9844b..0d493e6539 100644 --- a/uv.lock +++ b/uv.lock @@ -7163,8 +7163,8 @@ tooltalk = [ requires-dist = [ { name = "datasets", marker = "extra == 'agent-leaderboard'", specifier = "~=4.4" }, { name = "nemo-evaluator", marker = "extra == 'byob'", specifier = "~=0.1" }, - { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard", "bfcl", "byob", "tooltalk"], marker = "extra == 'all'", specifier = "==1.6.0.dev51+gab4c3030" }, - { name = "nvidia-nat-benchmarks", extras = ["all"], marker = "extra == 'test'", specifier = "==1.6.0.dev51+gab4c3030" }, + { name = "nvidia-nat-benchmarks", extras = ["agent-leaderboard", "bfcl", "byob", "tooltalk"], marker = "extra == 'all'", specifier = "==1.6.0.dev52+g385376c7" }, + { name = "nvidia-nat-benchmarks", extras = ["all"], marker = "extra == 'test'", specifier = "==1.6.0.dev52+g385376c7" }, { name = "nvidia-nat-core", editable = "packages/nvidia_nat_core" }, { name = "nvidia-nat-core", extras = ["async-endpoints"], marker = "extra == 'test'", editable = "packages/nvidia_nat_core" }, { name = "nvidia-nat-eval", editable = "packages/nvidia_nat_eval" }, From b3973bf8e8fd067fabb08b991fce46100c75415b Mon Sep 17 00:00:00 2001 From: Bryan Bednarski Date: Sun, 8 Mar 2026 22:41:07 -0700 Subject: [PATCH 10/10] update ToC Signed-off-by: Bryan Bednarski --- .../benchmarks/agent_leaderboard/README.md | 32 ++----------------- examples/benchmarks/bfcl/pyproject.toml | 1 - 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/examples/benchmarks/agent_leaderboard/README.md b/examples/benchmarks/agent_leaderboard/README.md index 21ef4f71a1..8980420a3e 100644 --- a/examples/benchmarks/agent_leaderboard/README.md +++ b/examples/benchmarks/agent_leaderboard/README.md @@ -33,8 +33,7 @@ Evaluate NeMo Agent Toolkit agent workflows against the [Galileo Agent Leaderboa - [Installation](#installation) - [Set Up Environment](#set-up-environment) -- [Option A: Download Dataset First](#option-a-download-dataset-first) -- [Option B: Auto-Download from HuggingFace](#option-b-auto-download-from-huggingface) +- [Auto-Download from HuggingFace](#auto-download-from-huggingface) - [Run Evaluation](#run-evaluation) - [Understanding Results](#understanding-results) - [All Domains Evaluation](#all-domains-evaluation) @@ -59,34 +58,7 @@ export NVIDIA_API_KEY= --- -## Option A: Download Dataset First - -Use the download script to fetch and transform the dataset: - -```bash -python examples/dynamo_integration/scripts/download_agent_leaderboard_v2.py \ - --output-dir data/agent_leaderboard \ - --domains banking -``` - -**Expected output:** -``` -INFO - Loading agent leaderboard v2 dataset from Hugging Face... -INFO - Loading domain: banking -INFO - Loaded 20 tools, 20 personas, 100 scenarios for banking -INFO - Saved 100 entries to data/agent_leaderboard/agent_leaderboard_v2_banking.json -INFO - Saved raw data to data/agent_leaderboard/raw/banking -``` - -Then set the data path: - -```bash -export AGENT_LEADERBOARD_DATA=data/agent_leaderboard/agent_leaderboard_v2_banking.json -``` - ---- - -## Option B: Auto-Download from HuggingFace +## Auto-Download from HuggingFace If no local file is found, the dataset loader downloads directly from HuggingFace. Just point `file_path` to a non-existent path and the `domains` config will be used to download: diff --git a/examples/benchmarks/bfcl/pyproject.toml b/examples/benchmarks/bfcl/pyproject.toml index 3b04ad2a0e..16b1c44502 100644 --- a/examples/benchmarks/bfcl/pyproject.toml +++ b/examples/benchmarks/bfcl/pyproject.toml @@ -40,4 +40,3 @@ dependencies = [ [tool.uv.sources] nvidia-nat = { path = "../../..", editable = true } nvidia-nat-benchmarks = { path = "../../../packages/nvidia_nat_benchmarks", editable = true } -