From bf22d4f0433af790872ac9d8ff8abcd1f79416cc Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Wed, 10 Jun 2026 23:35:53 -0700 Subject: [PATCH 01/44] squash #2700 Signed-off-by: Yuki Huang Co-authored-by: Akash Mehra --- nemo_rl/algorithms/single_controller.py | 660 +++++++++ nemo_rl/algorithms/staleness_sampler.py | 201 +++ nemo_rl/data_plane/interfaces.py | 25 + nemo_rl/data_plane/worker_mixin.py | 79 + nemo_rl/models/policy/tq_policy.py | 125 ++ .../policy/workers/megatron_policy_worker.py | 377 +++++ pyrefly.toml | 3 + .../test_single_controller_dryrun.py | 1291 +++++++++++++++++ .../unit/algorithms/test_staleness_sampler.py | 177 +++ tests/unit/data_plane/test_kvbatchmeta.py | 90 ++ .../policy/test_megatron_split_state.py | 638 ++++++++ 11 files changed, 3666 insertions(+) create mode 100644 nemo_rl/algorithms/single_controller.py create mode 100644 nemo_rl/algorithms/staleness_sampler.py create mode 100644 tests/unit/algorithms/test_single_controller_dryrun.py create mode 100644 tests/unit/algorithms/test_staleness_sampler.py create mode 100644 tests/unit/models/policy/test_megatron_split_state.py diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py new file mode 100644 index 00000000000..fb4e9051850 --- /dev/null +++ b/nemo_rl/algorithms/single_controller.py @@ -0,0 +1,660 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""SingleController: asyncio-based orchestrator for the RL training loop. + +SingleController is a CPU-only Ray actor that owns three concurrent asyncio +pumps and coordinates all other actors via lightweight RPCs. Other actors +expose methods and wait to be called. + +Key invariant: SC does not run model work. It sends control signals +(``KVBatchMeta`` and actor handles) and reads metadata. When advantage +calculation is enabled, SC fetches only the configured advantage input +columns, computes advantages, and writes that small derived column back to +DataPlane. Model tensors still move through DataPlane or NCCL. + +Data flow: + _rollout_pump → gen.generate_and_push(prompt, dp_client) ← RPC to GenWorker + GenWorker → dp_client.put_samples(...) + _train_pump → dp_client.claim_meta(...) → StalenessSampler + → _advantage_pump(meta) → dp_client.get_samples(...) + → adv_estimator.compute_advantage(...) + → dp_client.put_samples(...) + → trainer.train_from_meta(meta) + Trainer → dp_client.get_samples(...) (via its own client) + → dp_client.clear_samples(...) ← SC clears after train + _sync_weights → drain _inflight_rollouts → WeightSynchronizer.sync_weights() +""" + +from __future__ import annotations + +import asyncio +import logging +import time +from dataclasses import dataclass, field +from typing import Any, Literal, Optional + +import ray +import torch +from tensordict import TensorDict + +from nemo_rl.algorithms.staleness_sampler import ( + StalenessSampler, + count_prompt_groups, + min_weight_version, +) +from nemo_rl.data_plane import KVBatchMeta + +log = logging.getLogger(__name__) + + +@dataclass +class SingleControllerConfig: + """Configuration for SingleController.""" + + # Staleness + max_weight_staleness_versions: int = 1 + min_prompt_groups_per_batch: int = 2 + target_prompt_groups_per_step: Optional[int] = None + generations_per_prompt: int = 4 + batch_selection_strategy: Literal[ + "strict_on_policy", + "staleness_window", + ] = "strict_on_policy" + + # Concurrency limits + max_inflight_prompts: int = 8 + max_buffered_rollouts: int = 8 # _buffer_capacity semaphore size + + # Training + max_train_steps: int = 10 + max_rollout_prompts: int = 32 + + # DataPlane partition + partition_id: str = "rollout_data" + consumer_task_name: str = "train" + claim_required_fields: list[str] = field(default_factory=lambda: ["input_ids"]) + max_claim_prompt_groups: int = 8 + + # Advantage calculation + advantage_enabled: bool = False + advantage_output_field: str = "advantages" + advantage_prompt_ids_field: str = "prompt_ids_for_adv" + advantage_reward_field: str = "total_reward" + advantage_token_mask_field: str = "token_mask" + advantage_sample_mask_field: str = "sample_mask" + advantage_repeated_batch_fields: list[str] = field(default_factory=list) + advantage_policy_logprobs_field: str | None = None + advantage_reference_logprobs_field: str | None = None + + # Diagnostics + diagnostics: bool = False + + # Weight transport backend ("stub" for dry-run, "nccl" for production) + weight_transport: str = "stub" + weight_nccl_addr: str = "127.0.0.1" + weight_nccl_port: Optional[int] = None + + # Extra fields passed through to avoid TypedDict issues + extra: dict = field(default_factory=dict) + + +@ray.remote(num_cpus=1, num_gpus=0) # pragma: no cover +class SingleControllerActor: + """CPU-only Ray actor that orchestrates the RL training loop. + + Owns three concurrent asyncio tasks: + - _rollout_pump: dispatches prompts to GenerationWorkerActor + - _train_pump: claims DataPlane meta, trains, clears consumed rows + - _sync_weights: drain gate + weight synchronization + + All other actors are passive — they expose methods and wait to be called. + """ + + def __init__( + self, + cfg: SingleControllerConfig, + prompts: list[str], + dp_client_handle: Any, + gen_handle: Any, + trainer_handle: Any, + weight_synchronizer: Any, + advantage_estimator: Any | None = None, + ) -> None: + import logging as _logging + + _logging.basicConfig( + level=_logging.INFO, + format="[%(asctime)s] %(levelname)s %(filename)s:%(lineno)d: %(message)s", + ) + + self._cfg = cfg + self._prompts = prompts + self._dp_client = dp_client_handle + self._gen = gen_handle + self._trainer = trainer_handle + self._weight_synchronizer = weight_synchronizer + self._advantage_estimator = advantage_estimator + + if cfg.advantage_enabled and self._advantage_estimator is None: + raise ValueError( + "advantage_enabled=True requires an advantage_estimator instance" + ) + + # Initialize sampler + assert cfg.batch_selection_strategy in [ + "strict_on_policy", + "staleness_window", + ], f"Unknown batch_selection_strategy: {cfg.batch_selection_strategy}" + + if cfg.batch_selection_strategy == "strict_on_policy": + cfg.max_weight_staleness_versions = 0 + print( + "Using strict_on_policy, auto setting max_weight_staleness_versions to 0." + ) + if cfg.target_prompt_groups_per_step is None: + cfg.target_prompt_groups_per_step = cfg.min_prompt_groups_per_batch + if cfg.target_prompt_groups_per_step < cfg.min_prompt_groups_per_batch: + raise ValueError( + f"target_prompt_groups_per_step ({cfg.target_prompt_groups_per_step}) " + f"must be >= min_prompt_groups_per_batch ({cfg.min_prompt_groups_per_batch})" + ) + self._sampler = StalenessSampler(cfg.max_weight_staleness_versions) + + # ── asyncio state ────────────────────────────────────────────────── + # Gate: cleared during _sync_weights, set when generation may proceed + self._rollout_permitted: asyncio.Event = asyncio.Event() + self._rollout_permitted.set() + + # Count of in-flight generate_and_push calls + self._inflight_rollouts: int = 0 + + # Backpressure valve: max unconsumed rollout groups allowed in DataPlane. + # Acquired before each rollout dispatch; released after clear_samples. + self._buffer_capacity: asyncio.Semaphore = asyncio.Semaphore( + cfg.max_buffered_rollouts + ) + + self._trainer_version: int = 0 + self._train_steps: int = 0 + self._rollout_done: bool = False + self._claimed_meta: KVBatchMeta | None = None + self._step_consumed_sample_ids: list[str] = [] + + log.info( + "SingleControllerActor: staleness_cap=%d buffer=%d inflight=%d transport=%s", + cfg.max_weight_staleness_versions, + cfg.max_buffered_rollouts, + cfg.max_inflight_prompts, + cfg.weight_transport, + ) + + # ── public API ───────────────────────────────────────────────────────── + + async def run(self) -> dict[str, Any]: + """Main entry point. Runs until max_train_steps is reached.""" + rollout_task = asyncio.create_task(self._rollout_pump()) + train_task = asyncio.create_task(self._train_pump()) + + await train_task + + rollout_task.cancel() + try: + await rollout_task + except asyncio.CancelledError: + pass + + return { + "train_steps": self._train_steps, + "trainer_version": self._trainer_version, + } + + async def ping(self) -> dict[str, Any]: + """Liveness check — returns immediately if event loop is running.""" + return { + "alive": True, + "trainer_version": self._trainer_version, + "train_steps": self._train_steps, + "inflight_rollouts": self._inflight_rollouts, + "rollout_permitted": self._rollout_permitted.is_set(), + } + + # ── internal helpers ─────────────────────────────────────────────────── + + async def _ray_get(self, obj_ref: Any) -> Any: + """Await a Ray ObjectRef without blocking the asyncio event loop.""" + return await obj_ref + + async def _reap_in_flight_nonblocking( + self, refs: list[ray.ObjectRef] + ) -> list[ray.ObjectRef]: + """Drain completed refs without blocking; return still-pending refs. + + Uses ``asyncio.wait`` with ``timeout=0`` so Ray ObjectRefs are checked + through their awaitable interface (which is accurate in async actors). + ``ray.wait(timeout=0)`` does not always reflect cross-process ref + readiness from an async actor, so we avoid it here. + """ + if not refs: + return [] + ref_to_task = {ref: asyncio.ensure_future(ref) for ref in refs} + await asyncio.wait(ref_to_task.values(), timeout=0.05) + pending: list[ray.ObjectRef] = [] + for ref, task in ref_to_task.items(): + if task.done(): + task.result() # surface exceptions; payload ignored + else: + task.cancel() + pending.append(ref) + return pending + + async def _call_dp(self, method_name: str, **kwargs) -> Any: + """Call a DataPlaneClient method or a Ray actor exposing that method.""" + method = getattr(self._dp_client, method_name) + remote = getattr(method, "remote", None) + if remote is not None: + return await self._ray_get(remote(**kwargs)) + result = method(**kwargs) + if asyncio.iscoroutine(result): + return await result + return result + + # ── the four pumps (three main pumps + advantage pump) ───────────────── + + async def _rollout_pump(self) -> None: + """Dispatch prompts as concurrent coroutines, one per prompt group. + + Flow per prompt: + 1. Acquire _buffer_capacity slot (backpressure) + 2. Wait for _rollout_permitted (paused during weight sync) + 3. Call gen.generate_and_push(prompt, dp_client) — RPC to GenWorker + GenWorker generates and calls DataPlane put_samples directly + 4. Decrement _inflight_rollouts + """ + n = self._cfg.max_rollout_prompts + sem = asyncio.Semaphore(self._cfg.max_inflight_prompts) + + start = time.monotonic() + log.info("rollout_pump: dispatching %d prompts", n) + + async def _one_group(prompt: str) -> None: + await self._buffer_capacity.acquire() + await self._rollout_permitted.wait() + async with sem: + self._inflight_rollouts += 1 + try: + await self._ray_get( + self._gen.generate_and_push.remote(prompt, self._dp_client) + ) + if self._cfg.diagnostics: + log.info(" rollout done for prompt='%s...'", prompt[:20]) + finally: + self._inflight_rollouts -= 1 + + tasks = [ + asyncio.ensure_future(_one_group(self._prompts[i % len(self._prompts)])) + for i in range(n) + ] + await asyncio.gather(*tasks) + + self._rollout_done = True + log.info( + "rollout_pump: finished %d prompts in %.2fs", + n, + time.monotonic() - start, + ) + + async def _train_pump(self) -> None: + """Per-prompt-group streaming train loop. + + Per step: + - Lazy ``begin_train_step`` on first ready group. + - Per ready group: optional ``prepare_logprobs_from_meta`` → + ``_advantage_pump`` → ``train_microbatch_from_meta`` (queued). + - End-of-step: drain in-flight → ``finish_train_step`` → + single ``clear_samples`` → ``_sync_weights``. + """ + logprobs_required = ( + self._cfg.advantage_policy_logprobs_field is not None + or self._cfg.advantage_reference_logprobs_field is not None + ) + + while self._train_steps < self._cfg.max_train_steps: + step_id = f"sc-step-{self._train_steps:06d}" + # __init__ coerces None → min_prompt_groups_per_batch (int); + # the assert narrows the Optional[int] type for pyrefly. + assert self._cfg.target_prompt_groups_per_step is not None + target_groups: int = self._cfg.target_prompt_groups_per_step + groups_dispatched = 0 + in_flight: list[ray.ObjectRef] = [] + step_open = False + step_min_weight_version: int | None = None + + while groups_dispatched < target_groups: + await asyncio.sleep(0) + await self._claim_available_meta() + evicted_meta = await self._evict_stale_claimed() + if evicted_meta is not None: + evicted_groups = count_prompt_groups( + evicted_meta, + generations_per_prompt=self._cfg.generations_per_prompt, + ) + for _ in range(evicted_groups): + self._buffer_capacity.release() + + group_indices = None + if self._claimed_meta is not None and self._claimed_meta.size > 0: + group_indices = self._sampler.select_one_group( + self._claimed_meta, + trainer_version=self._trainer_version, + generations_per_prompt=self._cfg.generations_per_prompt, + ) + + if group_indices is None: + in_flight = await self._reap_in_flight_nonblocking(in_flight) + if ( + self._rollout_done + and len(in_flight) == 0 + and (self._claimed_meta is None or self._claimed_meta.size == 0) + ): + break + await asyncio.sleep(0.005) + continue + + group_meta = self._claimed_meta.subset(group_indices) + self._claimed_meta = self._claimed_meta.drop(group_indices) + + if logprobs_required: + await self._ray_get( + self._trainer.prepare_logprobs_from_meta.remote(group_meta) + ) + + group_meta = await self._advantage_pump(group_meta) + + if not step_open: + await self._ray_get(self._trainer.begin_train_step.remote(step_id)) + step_open = True + + future = self._trainer.train_microbatch_from_meta.remote( + step_id, group_meta + ) + in_flight.append(future) + groups_dispatched += 1 + self._buffer_capacity.release() + self._step_consumed_sample_ids.extend(group_meta.sample_ids) + group_min_v = min_weight_version(group_meta) + if group_min_v is not None: + step_min_weight_version = ( + group_min_v + if step_min_weight_version is None + else min(step_min_weight_version, group_min_v) + ) + + in_flight = await self._reap_in_flight_nonblocking(in_flight) + + for fut in in_flight: + await self._ray_get(fut) + + if not step_open: + log.info("train_pump: rollout exhausted before any group ready") + break + + result = await self._ray_get( + self._trainer.finish_train_step.remote(step_id) + ) + consumed_ids = list(self._step_consumed_sample_ids) + await self._call_dp( + "clear_samples", + sample_ids=consumed_ids, + partition_id=self._cfg.partition_id, + ) + self._step_consumed_sample_ids = [] + prev_trainer_version = self._trainer_version + self._trainer_version = result["trainer_version"] + lag = ( + prev_trainer_version - step_min_weight_version + if step_min_weight_version is not None + else 0 + ) + log.info( + "train step %d/%d trainer_v=%d lag=%d batch_size=%d", + self._train_steps + 1, + self._cfg.max_train_steps, + self._trainer_version, + lag, + len(consumed_ids), + ) + + await self._sync_weights() + self._train_steps += 1 + + async def _sync_weights(self) -> None: + """Drain in-flight rollouts then synchronize weights. + + SC owns the drain gate (when to sync); WeightSynchronizer owns how. + + Flow: + 1. _rollout_permitted.clear() — no new dispatches + 2. drain _inflight_rollouts → 0 (5ms poll) + 3. weight_synchronizer.sync_weights(trainer_version) + 4. _rollout_permitted.set() — resume + """ + self._rollout_permitted.clear() + + # Drain: wait for all in-flight rollouts to complete before NCCL + # Critical: if GenWorker has queued calls when NCCL init is dispatched, + # the init sits behind them — trainer blocks in rendezvous → deadlock + drain_start = time.monotonic() + while self._inflight_rollouts > 0: + await asyncio.sleep(0.005) + + drain_elapsed = time.monotonic() - drain_start + log.info( + " _sync_weights: drained in %.3fs, syncing weights v%d", + drain_elapsed, + self._trainer_version, + ) + + t0 = time.monotonic() + await self._weight_synchronizer.sync_weights(self._trainer_version) + elapsed = time.monotonic() - t0 + + log.info(" _sync_weights: sync done in %.3fs", elapsed) + self._rollout_permitted.set() + + async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: + """Fetch advantage inputs, compute advantages, and write them back. + + SC owns the prompt-group-scoped advantage stage because the selected + ``KVBatchMeta`` still contains complete prompt groups before trainer + DP sharding. Tensor payloads still move through DataPlane: SC fetches + only the configured advantage input columns and writes the computed + ``advantages`` column back under the same ``sample_ids``. + """ + if not self._cfg.advantage_enabled: + return meta + assert self._advantage_estimator is not None + + data = await self._call_dp( + "get_samples", + sample_ids=meta.sample_ids, + partition_id=meta.partition_id, + select_fields=self._advantage_input_fields(), + ) + + prompt_ids = _tensor_field(data, self._cfg.advantage_prompt_ids_field) + rewards = _squeeze_trailing_unit_dim( + _tensor_field(data, self._cfg.advantage_reward_field) + ).float() + token_mask = _tensor_field(data, self._cfg.advantage_token_mask_field).float() + sample_mask = _squeeze_trailing_unit_dim( + _tensor_field(data, self._cfg.advantage_sample_mask_field) + ).float() + mask = token_mask * sample_mask.unsqueeze(-1) + + repeated_batch: dict[str, torch.Tensor] = { + "total_reward": rewards, + } + for field_name in self._cfg.advantage_repeated_batch_fields: + repeated_batch[field_name] = _squeeze_trailing_unit_dim( + _tensor_field(data, field_name) + ) + + kwargs: dict[str, torch.Tensor] = {} + if self._cfg.advantage_policy_logprobs_field is not None: + kwargs["logprobs_policy"] = _tensor_field( + data, + self._cfg.advantage_policy_logprobs_field, + ) + if self._cfg.advantage_reference_logprobs_field is not None: + kwargs["logprobs_reference"] = _tensor_field( + data, + self._cfg.advantage_reference_logprobs_field, + ) + + advantages = self._advantage_estimator.compute_advantage( + prompt_ids=prompt_ids, + rewards=rewards, + mask=mask, + repeated_batch=repeated_batch, + **kwargs, + ) + + await self._call_dp( + "put_samples", + sample_ids=meta.sample_ids, + partition_id=meta.partition_id, + fields=_fields_for_put( + meta, + {self._cfg.advantage_output_field: advantages}, + ), + ) + return meta.with_fields([self._cfg.advantage_output_field]) + + # ── utility helpers ──────────────────────────────────────────────────── + + async def _claim_available_meta(self) -> None: + """Claim currently-ready rows and append them to the local scheduler cache. + + TODO: replace this with a non-consuming metadata listing API. + ``claim_meta`` advances TQ's per-task cursor, so SC must keep a + local cache of claimed-but-not-yet-trained samples for now. + """ + batch_size = ( + self._cfg.max_claim_prompt_groups * self._cfg.generations_per_prompt + ) + meta = await self._call_dp( + "claim_meta", + partition_id=self._cfg.partition_id, + task_name=self._cfg.consumer_task_name, + required_fields=self._claim_required_fields(), + batch_size=batch_size, + blocking=False, + timeout_s=0.0, + ) + if meta.size == 0: + return + if self._claimed_meta is None or self._claimed_meta.size == 0: + self._claimed_meta = meta + else: + self._claimed_meta = self._claimed_meta.concat(meta) + + def _claim_required_fields(self) -> list[str]: + fields = list(self._cfg.claim_required_fields) + if self._cfg.advantage_enabled: + fields.extend(self._advantage_input_fields()) + return list(dict.fromkeys(fields)) + + def _advantage_input_fields(self) -> list[str]: + fields = [ + self._cfg.advantage_prompt_ids_field, + self._cfg.advantage_reward_field, + self._cfg.advantage_token_mask_field, + self._cfg.advantage_sample_mask_field, + *self._cfg.advantage_repeated_batch_fields, + ] + if self._cfg.advantage_policy_logprobs_field is not None: + fields.append(self._cfg.advantage_policy_logprobs_field) + if self._cfg.advantage_reference_logprobs_field is not None: + fields.append(self._cfg.advantage_reference_logprobs_field) + return list(dict.fromkeys(fields)) + + async def _evict_stale_claimed(self) -> KVBatchMeta | None: + if self._claimed_meta is None or self._claimed_meta.size == 0: + return None + indices = self._sampler.evictable_indices( + self._claimed_meta, + trainer_version=self._trainer_version, + generations_per_prompt=self._cfg.generations_per_prompt, + ) + if not indices: + return None + evicted_meta = self._claimed_meta.subset(indices) + log.info( + " evicting %d stale samples from %d prompt group(s)", + evicted_meta.size, + count_prompt_groups( + evicted_meta, + generations_per_prompt=self._cfg.generations_per_prompt, + ), + ) + await self._call_dp( + "clear_samples", + sample_ids=evicted_meta.sample_ids, + partition_id=evicted_meta.partition_id, + ) + self._claimed_meta = self._claimed_meta.drop(indices) + return evicted_meta + + +def _tensor_field(data: TensorDict, field_name: str) -> torch.Tensor: + value = data[field_name] + if not isinstance(value, torch.Tensor): + raise TypeError( + f"advantage_pump expected tensor field {field_name!r}; got {type(value)}" + ) + if value.is_nested: + return torch.nested.to_padded_tensor(value, padding=0) + return value + + +def _squeeze_trailing_unit_dim(value: torch.Tensor) -> torch.Tensor: + if value.dim() >= 2 and value.shape[-1] == 1: + return value.squeeze(-1) + return value + + +def _fields_for_put(meta: KVBatchMeta, fields: dict[str, torch.Tensor]) -> TensorDict: + packed: dict[str, torch.Tensor] = {} + if meta.sequence_lengths is None: + for field_name, value in fields.items(): + packed[field_name] = value.detach().contiguous() + # pyrefly: ignore[bad-argument-type] + return TensorDict(packed, batch_size=[meta.size]) + + lengths = torch.tensor(meta.sequence_lengths, dtype=torch.long) + for field_name, value in fields.items(): + if value.dim() >= 2 and value.shape[1] == int(lengths.max().item()): + rows = [ + value[i, : int(lengths[i].item())].detach().contiguous() + for i in range(meta.size) + ] + packed[field_name] = torch.nested.as_nested_tensor( + rows, + layout=torch.jagged, + ) + else: + packed[field_name] = value.detach().contiguous() + # pyrefly: ignore[bad-argument-type] + return TensorDict(packed, batch_size=[meta.size]) diff --git a/nemo_rl/algorithms/staleness_sampler.py b/nemo_rl/algorithms/staleness_sampler.py new file mode 100644 index 00000000000..ed48a3d0fee --- /dev/null +++ b/nemo_rl/algorithms/staleness_sampler.py @@ -0,0 +1,201 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Prompt-group batch selection strategies for SingleController metadata.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Optional + +from nemo_rl.data_plane import KVBatchMeta + + +@dataclass(frozen=True) +class PromptGroup: + """Indices and scheduling metadata for one prompt group.""" + + group_id: str + indices: list[int] + weight_version: int | None + committed: bool + expected_num_samples: int + + @property + def is_complete(self) -> bool: + return len(self.indices) == self.expected_num_samples + + +class StalenessSampler: + """Select complete prompt groups inside a version staleness window.""" + + def __init__(self, max_staleness_versions: int): + self.max_staleness_versions = max_staleness_versions + + def select_indices( + self, + meta: KVBatchMeta, + *, + trainer_version: int, + min_prompt_groups: int, + generations_per_prompt: int, + ) -> Optional[list[int]]: + eligible: list[tuple[int, int, PromptGroup]] = [] + for group in _prompt_groups(meta, generations_per_prompt): + if not group.committed or not group.is_complete: + continue + if group.weight_version is None or group.weight_version > trainer_version: + continue + lag = trainer_version - group.weight_version + if lag > self.max_staleness_versions: + continue + eligible.append((lag, group.indices[0], group)) + + if len(eligible) < min_prompt_groups: + return None + + eligible.sort(key=lambda item: (item[0], item[1])) + groups = [item[2] for item in eligible[:min_prompt_groups]] + return _flatten_group_indices(groups) + + def select_one_group( + self, + meta: KVBatchMeta, + *, + trainer_version: int, + generations_per_prompt: int, + ) -> Optional[list[int]]: + eligible: list[tuple[int, int, PromptGroup]] = [] + for group in _prompt_groups(meta, generations_per_prompt): + if not group.committed or not group.is_complete: + continue + if group.weight_version is None or group.weight_version > trainer_version: + continue + lag = trainer_version - group.weight_version + if lag > self.max_staleness_versions: + continue + eligible.append((lag, group.indices[0], group)) + + if not eligible: + return None + + eligible.sort(key=lambda item: (item[0], item[1])) + return _flatten_group_indices([eligible[0][2]]) + + def evictable_indices( + self, + meta: KVBatchMeta, + *, + trainer_version: int, + generations_per_prompt: int, + ) -> list[int]: + groups = [] + for group in _prompt_groups(meta, generations_per_prompt): + if group.weight_version is None or not group.is_complete: + continue + lag = trainer_version - group.weight_version + if lag > self.max_staleness_versions: + groups.append(group) + return _flatten_group_indices(groups) + + +def count_prompt_groups( + meta: KVBatchMeta, + *, + generations_per_prompt: int, +) -> int: + """Count complete prompt groups represented by ``meta``.""" + return sum( + 1 for group in _prompt_groups(meta, generations_per_prompt) if group.is_complete + ) + + +def min_weight_version(meta: KVBatchMeta) -> int | None: + """Smallest ``weight_version`` across per-sample tags, or None if absent.""" + versions = [ + v for v in (_weight_version(tag) for tag in meta.tags or []) if v is not None + ] + return min(versions) if versions else None + + +def _prompt_groups( + meta: KVBatchMeta, + generations_per_prompt: int, +) -> list[PromptGroup]: + tags = meta.tags or [{} for _ in meta.sample_ids] + grouped: dict[str, list[int]] = {} + first_tag: dict[str, dict] = {} + + for idx, sample_id in enumerate(meta.sample_ids): + tag = tags[idx] if idx < len(tags) else {} + group_id = str(tag.get("group_id") or _group_id_from_sample_id(sample_id)) + grouped.setdefault(group_id, []).append(idx) + first_tag.setdefault(group_id, tag) + + groups: list[PromptGroup] = [] + for group_id, indices in grouped.items(): + tag = first_tag[group_id] + expected = _as_int( + tag.get( + "expected_num_samples", + tag.get( + "expected_num_keys", + tag.get("generations_per_prompt", generations_per_prompt), + ), + ) + ) + groups.append( + PromptGroup( + group_id=group_id, + indices=indices, + weight_version=_weight_version(tag), + committed=_as_bool(tag.get("committed", True)), + expected_num_samples=expected or generations_per_prompt, + ) + ) + groups.sort(key=lambda group: group.indices[0]) + return groups + + +def _flatten_group_indices(groups: list[PromptGroup]) -> list[int]: + return [idx for group in groups for idx in group.indices] + + +def _group_id_from_sample_id(sample_id: str) -> str: + prefix, sep, suffix = sample_id.rpartition("_g") + if sep and suffix.isdigit(): + return prefix + return sample_id + + +def _weight_version(tag: dict) -> int | None: + value = tag.get("weight_version", tag.get("version")) + return _as_int(value) + + +def _as_int(value) -> int | None: + if value is None: + return None + try: + return int(value) + except (TypeError, ValueError): + return None + + +def _as_bool(value) -> bool: + if isinstance(value, bool): + return value + if isinstance(value, str): + return value.lower() in {"1", "true", "yes"} + return bool(value) diff --git a/nemo_rl/data_plane/interfaces.py b/nemo_rl/data_plane/interfaces.py index 6bdc5e940cf..41a98f0c0ed 100644 --- a/nemo_rl/data_plane/interfaces.py +++ b/nemo_rl/data_plane/interfaces.py @@ -219,6 +219,31 @@ def concat(self, *others: "KVBatchMeta") -> "KVBatchMeta": sample_ids=sample_ids, sequence_lengths=seq_lens, tags=tags ) + def drop(self, indices: "Sequence[int]") -> "KVBatchMeta | None": + """Complement of :meth:`subset`. Returns ``None`` when all rows are dropped.""" + dropped = set(indices) + keep = [i for i in range(self.size) if i not in dropped] + if not keep: + return None + return self.subset(keep) + + def with_fields(self, field_names: "Sequence[str]") -> "KVBatchMeta": + """Return a copy with ``field_names`` merged into ``fields`` (deduped, order-preserving).""" + merged = list(dict.fromkeys([*(self.fields or []), *field_names])) + return KVBatchMeta( + partition_id=self.partition_id, + task_name=self.task_name, + sample_ids=list(self.sample_ids), + fields=merged, + sequence_lengths=( + list(self.sequence_lengths) + if self.sequence_lengths is not None + else None + ), + extra_info=dict(self.extra_info or {}), + tags=[dict(tag) for tag in self.tags] if self.tags is not None else None, + ) + class DataPlaneClient(ABC): """Stable, swappable data-plane boundary. diff --git a/nemo_rl/data_plane/worker_mixin.py b/nemo_rl/data_plane/worker_mixin.py index 89c0cb622d1..8546336590c 100644 --- a/nemo_rl/data_plane/worker_mixin.py +++ b/nemo_rl/data_plane/worker_mixin.py @@ -516,3 +516,82 @@ def get_reference_policy_logprobs_presharded( tq_field="reference_policy_logprobs", ) del result + + # ── split-API entrypoints (SC async path) ────────────────────────────── + # + # The split path lets SingleController drive forward/backward per + # microbatch (or per pipeline-batch on Megatron) without stepping the + # optimizer until a full logical batch has accumulated. Backend + # methods (``begin_train_step``, ``train_microbatch``, + # ``finish_train_step``, ``abort_train_step``) own the train-step + # state machine; this mixin just gates them on TQ-presharded data. + + @wrap_with_nvtx_name("policy_worker/begin_train_step_presharded") + def begin_train_step_presharded( + self, + step_id: str, + loss_fn: Any, + gbs: Optional[int] = None, + mbs: Optional[int] = None, + ) -> None: + """Open a logical train step. No fetch — pure lifecycle. + + The backend stores ``step_id`` / ``loss_fn`` / ``gbs`` / ``mbs``, + clears gradients, and initialises accumulators for + ``local_valid_seqs`` / ``local_valid_toks`` and any per-microbatch + metrics. Optimizer state is untouched here. + """ + self.begin_train_step( # type: ignore[attr-defined] + step_id=step_id, + loss_fn=loss_fn, + gbs=gbs, + mbs=mbs, + ) + + @wrap_with_nvtx_name("policy_worker/train_microbatch_presharded") + def train_microbatch_presharded( + self, + step_id: str, + meta: "KVBatchMeta", + ) -> dict[str, Any]: + """Per-rank microbatch entrypoint. Fetch → packing prep → forward+backward. + + Gradients accumulate into ``.grad`` across calls; no + ``optimizer.step`` here. Returns per-microbatch metrics (loss, + local_valid_*); the backend folds them into the step accumulator + and the caller may surface them for diagnostics. + """ + data = self._fetch(meta) + data = self._attach_or_repack_pack_metadata(data, meta) + return self.train_microbatch( # type: ignore[attr-defined] + step_id=step_id, + data=data, + ) + + @wrap_with_nvtx_name("policy_worker/finish_train_step_presharded") + def finish_train_step_presharded( + self, + step_id: str, + ) -> dict[str, Any]: + """Close a logical train step. No fetch — pure lifecycle. + + Backend all-reduces accumulated ``local_valid_seqs/toks``, + rescales gradients to the final global normalization, runs grad + clip, steps the optimizer + scheduler, then zeros gradients. + Returns the aggregated step result (``loss``, ``grad_norm``, + ``all_mb_metrics``, …). + """ + return self.finish_train_step(step_id=step_id) # type: ignore[attr-defined] + + @wrap_with_nvtx_name("policy_worker/abort_train_step_presharded") + def abort_train_step_presharded( + self, + step_id: str, + ) -> None: + """Discard partial train-step state without stepping the optimizer. + + Used when SC decides the logical batch will not complete (e.g. + weight-sync triggered mid-step). Backend drops accumulators and + zeros gradients. + """ + self.abort_train_step(step_id=step_id) # type: ignore[attr-defined] diff --git a/nemo_rl/models/policy/tq_policy.py b/nemo_rl/models/policy/tq_policy.py index 1e4bc93ba09..61731f5ca50 100644 --- a/nemo_rl/models/policy/tq_policy.py +++ b/nemo_rl/models/policy/tq_policy.py @@ -457,3 +457,128 @@ def train_from_meta( warnings.warn(f"Error getting theoretical flops: {e}") return aggregated_results + + # ── split-API fanout (SC async path) ─────────────────────────────────── + # + # Counterpart to :meth:`train_from_meta`, exposed to ``PolicyTrainerActor`` + # so :class:`SingleControllerActor` can stream microbatches without + # forcing a full-step optimizer.step on every dispatch. + # + # Lifecycle: + # begin_train_step — open step; broadcast loss_fn/gbs/mbs + # train_microbatch_from_meta (N×) — DP-sharded fwd/bwd, grads accumulate + # finish_train_step — all_reduce + opt.step + sched.step + # abort_train_step — drop accumulators, no opt.step + # + # ``train_from_meta`` is unchanged and remains the sync entrypoint. + + def begin_train_step( + self, + step_id: str, + loss_fn: LossFunction, + gbs: Optional[int] = None, + mbs: Optional[int] = None, + ) -> None: + """Open a logical train step on every worker.""" + batch_size = gbs or self.cfg["train_global_batch_size"] + micro_batch_size = mbs or self.cfg["train_micro_batch_size"] + if self.flops_tracker is not None: + self.flops_tracker.reset() + futures = self.worker_group.run_all_workers_single_data( + "begin_train_step_presharded", + step_id=step_id, + loss_fn=loss_fn, + gbs=batch_size, + mbs=micro_batch_size, + ) + self.worker_group.get_all_worker_results(futures) + + def train_microbatch_from_meta( + self, + step_id: str, + meta: KVBatchMeta, + timer: Optional[Timer] = None, + ) -> dict[str, Any]: + """Dispatch one microbatch (DP-sharded) into an open train step. + + Mirrors the sharding logic of :meth:`train_from_meta` but without + a logical-batch sizing constraint: this routes ``meta`` to DP + ranks and runs forward+backward; gradients accumulate in + ``.grad``. The optimizer step happens at :meth:`finish_train_step`. + """ + self._stamp_pad_seqlen(meta) + spa, dba = self._packing_args("train_mb_tokens") + train_meta = replace( + meta, + fields=list(DP_TRAIN_FIELDS), + task_name="train", + ) + with timer.time("policy_training/shard_meta") if timer else nullcontext(): + dp_metas, _ = shard_meta_for_dp( + train_meta, + dp_world=self.sharding_annotations.get_axis_size("data_parallel"), + batch_size=None, + sequence_packing_args=spa, + dynamic_batching_args=dba, + ) + + if self.flops_tracker is not None: + for m in dp_metas: + self.flops_tracker.track_batch(list(m.sequence_lengths or [])) + + with ( + timer.time("policy_training/submit_microbatch_futures") + if timer + else nullcontext() + ): + futures = self.worker_group.run_all_workers_sharded_data( + "train_microbatch_presharded", + meta=dp_metas, + in_sharded_axes=["data_parallel"], + replicate_on_axes=[ + "context_parallel", + "tensor_parallel", + "pipeline_parallel", + ], + output_is_replicated=[ + "context_parallel", + "tensor_parallel", + "pipeline_parallel", + ], + common_kwargs={"step_id": step_id}, + ) + results = self.worker_group.get_all_worker_results(futures) + # Per-microbatch metrics: pass through DP-rank-0 by convention, + # backend may aggregate later if needed. Surface as-is for now. + return results[0] if results else {} + + def finish_train_step(self, step_id: str) -> dict[str, Any]: + """Close an open train step: all_reduce, rescale, optimizer.step. + + Aggregates per-rank step results into the same shape as + :meth:`train_from_meta` so callers don't have to special-case + the split path. + """ + futures = self.worker_group.run_all_workers_single_data( + "finish_train_step_presharded", + step_id=step_id, + ) + results = self.worker_group.get_all_worker_results(futures) + aggregated_results = _aggregate_train_results(results) + + if self.flops_tracker is not None: + aggregated_results["total_flops"] = self.flops_tracker.total_flops + aggregated_results["num_ranks"] = self.worker_group.cluster.world_size() + + return aggregated_results + + def abort_train_step(self, step_id: str) -> None: + """Drop partial step state on every worker. No optimizer.step.""" + futures = self.worker_group.run_all_workers_single_data( + "abort_train_step_presharded", + step_id=step_id, + ) + self.worker_group.get_all_worker_results(futures) + + if self.flops_tracker is not None: + self.flops_tracker.reset() diff --git a/nemo_rl/models/policy/workers/megatron_policy_worker.py b/nemo_rl/models/policy/workers/megatron_policy_worker.py index 0eec29f04a2..70253fbdcaf 100644 --- a/nemo_rl/models/policy/workers/megatron_policy_worker.py +++ b/nemo_rl/models/policy/workers/megatron_policy_worker.py @@ -143,6 +143,11 @@ class MegatronPolicyWorkerImpl( AbstractPolicyWorker, ColocatablePolicyInterface, ): + # Holds the split-API train-step state between begin/finish or + # begin/abort; None when no step is open. Declared at class level so + # ``self._train_step_state = None`` after finish/abort type-checks. + _train_step_state: Optional[dict[str, Any]] = None + def __repr__(self): """Customizes the actor's prefix in the Ray logs. @@ -835,6 +840,378 @@ def _set_moe_grad_scale_func(self, func): if config is not None: config.moe_grad_scale_func = func + # ── split-API train-step state machine (SingleController async path) ── + # + # Mirrors the v1/v2 implementations, adapted for mcore. Key differences: + # + # 1. mcore DDP accumulates ``param.main_grad`` per backward and dispatches + # a cross-DP reduce when ``is_last_microbatch=True`` (one per + # ``forward_backward_func`` call). Naively chaining multiple + # ``forward_backward_func`` calls between ``optimizer.step()`` would + # over-count: each call's terminal reduce sums an already-reduced + # bucket again. We wrap every call in ``self.model.no_sync()`` so + # hooks accumulate locally only; one explicit ``start_grad_sync`` + + # ``finish_grad_sync`` at finish does the single true reduce. + # 2. PP>1: the pipeline scheduler invokes ``config.grad_sync_func`` + # directly on last-microbatch boundaries — this bypasses the + # ``no_sync`` gate. We null it for the duration of the step and + # restore at finish/abort. + # 3. Grad clip is bundled inside ``MegatronOptimizer.step()``; the 1/N + # rescale via ``self.model.scale_gradients(1/N)`` must run before + # ``optimizer.step()`` so the clip operates on the rescaled grad. + # 4. With ``calculate_per_token_loss=True`` + ``average_in_collective= + # False``, mcore's DDP sums (does not average) grads across DP, so + # no FSDP-style ``loss *= dp_size*cp_size`` cancellation is needed + # per microbatch. + + def _split_step_state_init( + self, + step_id: str, + loss_fn: LossFunction, + gbs: Optional[int], + mbs: Optional[int], + ) -> dict[str, Any]: + from nemo_rl.algorithms.loss.interfaces import LossType + + return { + "step_id": step_id, + "loss_fn": loss_fn, + "loss_type": getattr(loss_fn, "loss_type", LossType.TOKEN_LEVEL), + "gbs": gbs or self.cfg["train_global_batch_size"], + "mbs": mbs or self.cfg["train_micro_batch_size"], + "local_valid_seqs": torch.zeros((), dtype=torch.float64, device="cuda"), + "local_valid_toks": torch.zeros((), dtype=torch.float64, device="cuda"), + "all_mb_metrics": [], + "mb_losses": [], + "total_num_microbatches": 0, + # Saved across the step so we can restore at finish/abort. + "saved_grad_sync_func": None, + "no_sync_active": False, + } + + def _assert_step_open(self, step_id: str) -> dict[str, Any]: + state = getattr(self, "_train_step_state", None) + if state is None: + raise RuntimeError( + f"no train step open; begin_train_step({step_id!r}) must be called first" + ) + if state["step_id"] != step_id: + raise RuntimeError( + f"step_id mismatch: open step is {state['step_id']!r}, got {step_id!r}" + ) + return state + + @wrap_with_nvtx_name("megatron_policy_worker/begin_train_step") + def begin_train_step( + self, + step_id: str, + loss_fn: LossFunction, + gbs: Optional[int] = None, + mbs: Optional[int] = None, + ) -> None: + existing = getattr(self, "_train_step_state", None) + if existing is not None: + raise RuntimeError( + f"train step {existing['step_id']!r} is already open; " + f"call finish_train_step or abort_train_step before begin" + ) + # Match sync train() inference-state reset (line 332-340). + if hasattr(self.model, "inference_params"): + self.model.inference_params = None + for module in self.model.modules(): + if hasattr(module, "reset_inference_cache"): + module.reset_inference_cache() + if hasattr(module, "_inference_key_value_memory"): + module._inference_key_value_memory = None + + self.model.train() + self.model.zero_grad_buffer() + self.optimizer.zero_grad() + + state = self._split_step_state_init( + step_id=step_id, loss_fn=loss_fn, gbs=gbs, mbs=mbs + ) + + # Suppress the PP scheduler's direct ``grad_sync_func`` call (which + # bypasses ``no_sync``). Save the existing value so we can restore + # at finish/abort. PP=1's ``forward_backward_no_pipelining`` doesn't + # invoke this; nulling it is a no-op there. + # Read "config" via getattr-by-string so the token stays out of + # begin_train_step.__code__.co_names; otherwise cloudpickle matches + # torch.distributed.config (a non-pickleable ConfigModuleInstance). + model_config = getattr(self.model, "config", None) + if model_config is not None: + state["saved_grad_sync_func"] = getattr( + model_config, "grad_sync_func", None + ) + model_config.grad_sync_func = None + else: + state["saved_grad_sync_func"] = None + + self._train_step_state = state + + @wrap_with_nvtx_name("megatron_policy_worker/train_microbatch") + def train_microbatch( + self, + step_id: str, + data: BatchedDataDict[Any], + ) -> dict[str, Any]: + """One DP slice of data → one ``forward_backward_func`` invocation. + + Wrapped in ``self.model.no_sync()`` so the mcore DDP hooks + accumulate ``param.main_grad`` locally on each rank without + dispatching a per-call DP reduce. The single true reduce is done + explicitly in ``finish_train_step``. + """ + state = self._assert_step_open(step_id) + loss_fn = state["loss_fn"] + + # Accumulate local mask sums for the finish-time all_reduce. + # Inlined from process_global_batch (data.py:319-332) — we can't + # call process_global_batch directly because it eagerly all_reduces + # the local sums, which is exactly what we're trying to defer. + assert "sample_mask" in data, "sample_mask required on microbatch data" + sample_mask = data["sample_mask"] + call_local_seqs = torch.sum(sample_mask).to(torch.float64) + if "token_mask" in data: + token_mask = data["token_mask"] + call_local_toks = torch.sum( + token_mask[:, 1:] * sample_mask.unsqueeze(-1) + ).to(torch.float64) + else: + call_local_toks = call_local_seqs * data["input_ids"].shape[1] + + state["local_valid_seqs"] = state["local_valid_seqs"] + call_local_seqs + state["local_valid_toks"] = state["local_valid_toks"] + call_local_toks + + # Build the per-call iterator. Each ``train_microbatch_from_meta`` + # call carries one DP slice; the iterator subdivides into pipeline + # microbatches. + ( + data_iterator, + num_microbatches, + micro_batch_size, + seq_length, + padded_seq_length, + ) = get_microbatch_iterator( + data, + self.cfg, + state["mbs"], + straggler_timer=self.mcore_state.straggler_timer, + ) + state["total_num_microbatches"] += int(num_microbatches) + + loss_post_processor = LossPostProcessor( + loss_fn=loss_fn, + cfg=self.cfg, + num_microbatches=num_microbatches, + sampling_params=self.sampling_params, + draft_model=self.draft_model, + ) + + # Placeholder N=1: loss returns un-normalized sums. ``backward`` + # deposits raw ``d(sum)/dθ`` into ``param.main_grad`` via the DDP + # hooks. The 1/N rescale happens once at finish. + placeholder_n = torch.tensor(1.0, device="cuda") + + draft_enabled = "draft" in self.cfg and self.cfg["draft"]["enabled"] + + # The critical wrap: hooks fire (accumulate main_grad) but the + # per-call reduce dispatch is gated off. + with self.model.no_sync(): + rerun_state_machine = get_rerun_state_machine() + while rerun_state_machine.should_run_forward_backward(data_iterator): + losses_reduced = megatron_forward_backward( + model=self.model, + data_iterator=data_iterator, + num_microbatches=num_microbatches, + seq_length=padded_seq_length, + mbs=micro_batch_size, + post_processing_fn=loss_post_processor, + forward_only=False, + defer_fp32_logits=self.defer_fp32_logits, + global_valid_seqs=placeholder_n, + global_valid_toks=placeholder_n, + sampling_params=self.sampling_params, + straggler_timer=self.mcore_state.straggler_timer, + draft_model=self.draft_model, + enable_hidden_capture=draft_enabled, + use_linear_ce_fusion_loss=self.cfg["megatron_cfg"].get( + "use_linear_ce_fusion_loss", False + ), + ) + + if self.cfg["megatron_cfg"]["empty_unused_memory_level"] >= 1: + torch.cuda.empty_cache() + + # Collect per-mb metrics from the last PP stage; broadcast to all + # PP ranks so non-last-stage ranks have something to all_reduce + # against at finish. Metrics carry the N=1 placeholder for now — + # ``finish_train_step`` rescales by the true 1/N. + if parallel_state.is_pipeline_last_stage(ignore_virtual=True): + mb_metrics_collected = [] + for x in losses_reduced: + mb_metrics_collected.append(dict(x)) + else: + mb_metrics_collected = None + + mb_metrics_collected = broadcast_loss_metrics_from_last_stage( + mb_metrics_collected + ) + + for m in mb_metrics_collected: + state["all_mb_metrics"].append(m) + # ``loss`` key is the un-normalized per-mb scalar; collect for + # the global_loss aggregation at finish. + if "loss" in m: + state["mb_losses"].append(m["loss"]) + + return { + "local_valid_seqs_mb": float(call_local_seqs.item()), + "local_valid_toks_mb": float(call_local_toks.item()), + "num_pipeline_microbatches": int(num_microbatches), + } + + @wrap_with_nvtx_name("megatron_policy_worker/finish_train_step") + def finish_train_step(self, step_id: str) -> dict[str, Any]: + from nemo_rl.algorithms.loss.interfaces import LossType + + state = self._assert_step_open(step_id) + + # All-reduce accumulated mask sums across DP to recover true N. + to_reduce = torch.stack( + [state["local_valid_seqs"], state["local_valid_toks"]] + ).to(torch.float64) + torch.distributed.all_reduce( + to_reduce, group=parallel_state.get_data_parallel_group() + ) + global_valid_seqs = to_reduce[0] + global_valid_toks = to_reduce[1] + + if state["loss_type"] == LossType.TOKEN_LEVEL: + n_true = global_valid_toks + else: + n_true = global_valid_seqs + n_safe = n_true if n_true.item() > 0 else torch.tensor(1.0, device="cuda") + inv_n = float((1.0 / n_safe).item()) + + # Rescale all locally-accumulated gradients by 1/N. The reduce + # below sees the rescaled grads; for all_reduce the result is the + # global mean grad; for reduce_scatter (dist-opt) it's the shard. + # Either way, opt.step sees the right-normalized gradient. + self.model.scale_gradients(inv_n) + + # The ONE true cross-DP reduce for the entire step. + self.model.start_grad_sync() + self.model.finish_grad_sync() + + # opt.step clips internally (clip_grad config); operates on the + # already-rescaled grad. Returns (success, grad_norm, num_zeros). + update_successful, grad_norm, num_zeros_in_grad = self.optimizer.step() + + pg_collection = get_pg_collection(self.model) + update_successful = logical_and_across_model_parallel_group( + update_successful, mp_group=pg_collection.mp + ) + grad_norm = reduce_max_stat_across_model_parallel_group( + grad_norm, mp_group=pg_collection.mp + ) + num_zeros_in_grad = reduce_max_stat_across_model_parallel_group( + num_zeros_in_grad, mp_group=pg_collection.mp + ) + + if self.cfg["megatron_cfg"]["empty_unused_memory_level"] >= 2: + torch.cuda.empty_cache() + + # Restore grad_sync_func before scheduler.step / further state. + # See begin_train_step for why .config is accessed by string. + finish_model_config = getattr(self.model, "config", None) + if finish_model_config is not None: + finish_model_config.grad_sync_func = state["saved_grad_sync_func"] + + # Scheduler increment matches sync path's ``increment=gbs``. + self.scheduler.step(increment=state["gbs"]) + + # Per-mb metrics were computed with N=1; rescale to match what the + # sync path produces. ``masked_mean`` is linear in 1/N so a single + # scalar multiply per metric recovers the normalized value. + rescaled_metrics: list[dict[str, Any]] = [] + curr_lr = self.scheduler.get_lr(self.optimizer.param_groups[0]) + curr_wd = self.scheduler.get_wd() + global_valid_seqs_f = float(global_valid_seqs.item()) + global_valid_toks_f = float(global_valid_toks.item()) + + for m in state["all_mb_metrics"]: + out: dict[str, Any] = {} + for k, v in m.items(): + if "_min" in k or "_max" in k: + out[k] = v + elif isinstance(v, torch.Tensor): + out[k] = v.detach() * inv_n + else: + out[k] = v * inv_n + out["lr"] = curr_lr + out["wd"] = curr_wd + out["global_valid_seqs"] = global_valid_seqs_f + out["global_valid_toks"] = global_valid_toks_f + rescaled_metrics.append(out) + + # Scale per-mb losses by 1/N and reduce per-call sums. + scaled_losses = [lv * inv_n for lv in state["mb_losses"]] + losses_to_aggregate = [torch.tensor(scaled_losses).sum().item()] + + mb_metrics, global_loss = aggregate_training_statistics( + all_mb_metrics=rescaled_metrics, + losses=losses_to_aggregate, + data_parallel_group=parallel_state.get_data_parallel_group(), + ) + + metrics = { + "global_loss": global_loss.cpu(), + "rank": torch.distributed.get_rank(), + "gpu_name": torch.cuda.get_device_name(), + "model_dtype": self.dtype, + "all_mb_metrics": mb_metrics, + "grad_norm": torch.tensor([grad_norm]), + } + + # MoE aux-loss metrics: same convention as sync train() — scale + # by the total pipeline-microbatch count accumulated across all + # train_microbatch calls. + model_config = getattr(self.model, "config", None) + num_moe_experts = getattr(model_config, "num_moe_experts", None) + if num_moe_experts is not None and num_moe_experts > 1: + moe_loss_scale = 1.0 / max(1, state["total_num_microbatches"]) + moe_metrics = get_moe_metrics( + loss_scale=moe_loss_scale, + per_layer_logging=self.cfg["megatron_cfg"]["moe_per_layer_logging"], + ) + if moe_metrics: + metrics["moe_metrics"] = moe_metrics + + self._train_step_state = None + return metrics + + @wrap_with_nvtx_name("megatron_policy_worker/abort_train_step") + def abort_train_step(self, step_id: str) -> None: + state = getattr(self, "_train_step_state", None) + if state is None: + return + if state["step_id"] != step_id: + raise RuntimeError( + f"abort_train_step({step_id!r}) does not match open step " + f"{state['step_id']!r}" + ) + # Restore grad_sync_func first so the model is back to a normal + # state before zero_grad_buffer touches anything. + # See begin_train_step for why .config is accessed by string. + abort_model_config = getattr(self.model, "config", None) + if abort_model_config is not None: + abort_model_config.grad_sync_func = state["saved_grad_sync_func"] + self.model.zero_grad_buffer() + self.optimizer.zero_grad() + self._train_step_state = None + @wrap_with_nvtx_name("megatron_policy_worker/get_reference_policy_logprobs") def get_reference_policy_logprobs( self, diff --git a/pyrefly.toml b/pyrefly.toml index bca7713e542..670c5ead087 100644 --- a/pyrefly.toml +++ b/pyrefly.toml @@ -51,6 +51,8 @@ project-includes = [ "nemo_rl/algorithms/loss/utils.py", "nemo_rl/algorithms/opd.py", "nemo_rl/algorithms/reward_functions.py", + "nemo_rl/algorithms/single_controller.py", + "nemo_rl/algorithms/staleness_sampler.py", "nemo_rl/algorithms/utils.py", "nemo_rl/algorithms/x_token/__init__.py", "nemo_rl/algorithms/x_token/utils.py", @@ -164,6 +166,7 @@ project-includes = [ "nemo_rl/models/generation/vllm/vllm_backend.py", "nemo_rl/models/huggingface/__init__.py", "nemo_rl/models/megatron/__init__.py", + "nemo_rl/models/megatron/draft/__init__.py", "nemo_rl/models/policy/__init__.py", "nemo_rl/models/policy/interfaces.py", "nemo_rl/models/policy/utils.py", diff --git a/tests/unit/algorithms/test_single_controller_dryrun.py b/tests/unit/algorithms/test_single_controller_dryrun.py new file mode 100644 index 00000000000..8f32f0ef22f --- /dev/null +++ b/tests/unit/algorithms/test_single_controller_dryrun.py @@ -0,0 +1,1291 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Dry-run tests for SingleController asyncio skeleton (C-03). + +Validates the three-pump asyncio architecture using stub actors with +configurable sleep latencies — no GPU, no real model weights required. + +Key questions answered: + - Do all 3 pumps run concurrently? (rollout_pump dispatches while + train_pump is "busy") + - Does buffer capacity correctly block rollout_pump when capacity is full? + - Does _rollout_permitted correctly pause dispatch during _sync_weights? + - RISK-06: does a blocking policy.train() call freeze the event loop? + (train_from_meta uses asyncio.sleep to simulate, so this is non-blocking + by construction in the dry-run — see dedicated RISK-06 test below) +""" + +from __future__ import annotations + +import asyncio +import os +import threading +import time +from typing import Any + +import pytest +import ray +import torch +from tensordict import TensorDict + +# ── Ray temp dir: must be SHORT on macOS (AF_UNIX path limit = 103 bytes) ─ +# Use a fixed short path under /tmp to avoid hitting the socket length limit. +_RAY_TEMP = "/tmp/nrl_sc_test" +os.makedirs(_RAY_TEMP, exist_ok=True) +os.environ["RAY_TEMP_DIR"] = _RAY_TEMP +os.environ["RAY_TMPDIR"] = _RAY_TEMP + +from nemo_rl.algorithms.single_controller import ( + SingleControllerActor, + SingleControllerConfig, +) +from nemo_rl.algorithms.staleness_sampler import StalenessSampler +from nemo_rl.data_plane import KVBatchMeta + +# ── Fake in-memory DataPlane ────────────────────────────────────────────── + + +@ray.remote(num_cpus=0) +class FakeDataPlaneActor: + """Minimal in-memory DataPlane actor for dry-run testing. + + Stores rows by sample_id and exposes the current DataPlane methods + SingleController uses: claim_meta, get_samples, and clear_samples. + Not production code — used only for C-03 dry-run validation. + """ + + def __init__(self, partition_id: str = "rollout_data"): + self._partition_id = partition_id + self._rows: dict[str, dict] = {} + self._consumed: dict[str, set[str]] = {} + self._lock = threading.Lock() + self._clear_calls: list[list[str]] = [] + + def put_samples( + self, + sample_ids: list[str], + partition_id: str, + fields: TensorDict | None = None, + tags: list[dict[str, Any]] | None = None, + ) -> KVBatchMeta: + assert partition_id == self._partition_id + with self._lock: + for i, sample_id in enumerate(sample_ids): + row_fields = set(fields.keys()) if fields is not None else set() + row = self._rows.setdefault( + sample_id, + { + "fields": set(), + "values": {}, + "tag": dict(tags[i]) if tags is not None else {}, + }, + ) + row["fields"].update(row_fields) + if tags is not None: + row["tag"] = dict(tags[i]) + if fields is not None: + for field_name in fields.keys(): + value = fields[field_name] + assert isinstance(value, torch.Tensor) + row["values"][field_name] = value[i].detach().clone() + return KVBatchMeta( + partition_id=partition_id, + task_name=None, + sample_ids=list(sample_ids), + fields=list(fields.keys()) if fields is not None else None, + tags=[dict(t) for t in tags] if tags is not None else None, + ) + + def claim_meta( + self, + partition_id: str, + task_name: str, + required_fields: list[str], + batch_size: int, + dp_rank: int | None = None, + blocking: bool = True, + timeout_s: float = 60.0, + ) -> KVBatchMeta: + del dp_rank, blocking, timeout_s + assert partition_id == self._partition_id + with self._lock: + consumed = self._consumed.setdefault(task_name, set()) + sample_ids: list[str] = [] + tags: list[dict[str, Any]] = [] + for sample_id, row in self._rows.items(): + if sample_id in consumed: + continue + if not all(field in row["fields"] for field in required_fields): + continue + sample_ids.append(sample_id) + tags.append(dict(row["tag"])) + if len(sample_ids) >= batch_size: + break + consumed.update(sample_ids) + return KVBatchMeta( + partition_id=partition_id, + task_name=task_name, + sample_ids=sample_ids, + fields=list(required_fields), + tags=tags if tags else None, + ) + + def get_samples( + self, + sample_ids: list[str], + partition_id: str, + select_fields: list[str], + ) -> TensorDict: + assert partition_id == self._partition_id + values: dict[str, torch.Tensor] = {} + with self._lock: + for field_name in select_fields: + rows = [] + for sample_id in sample_ids: + rows.append(self._rows[sample_id]["values"][field_name]) + values[field_name] = torch.stack(rows, dim=0) + return TensorDict( + values, + batch_size=[len(sample_ids)], + ) + + def clear_samples(self, sample_ids: list[str] | None, partition_id: str) -> None: + assert partition_id == self._partition_id + with self._lock: + ids = list(self._rows) if sample_ids is None else sample_ids + self._clear_calls.append(list(ids)) + for sample_id in ids: + self._rows.pop(sample_id, None) + for consumed in self._consumed.values(): + consumed.discard(sample_id) + + def get_clear_calls(self) -> list[list[str]]: + with self._lock: + return [list(c) for c in self._clear_calls] + + def depth(self) -> int: + with self._lock: + return len(self._rows) + + +# ── Dry-run stub actors ─────────────────────────────────────────────────── + + +@ray.remote(num_cpus=0) +class DryRunGenWorker: + """Stub GenerationWorkerActor. + + Implements the same interface as production GenWorker: + generate_and_push(prompt, dp_client) → pushes fake record to DataPlane + + Uses asyncio.sleep to simulate generation latency without blocking + the event loop. + """ + + def __init__(self, gen_latency_s: float = 0.1, weight_version: int = 0): + self._gen_latency_s = gen_latency_s + self._weight_version = weight_version + self._call_count = 0 + self._call_timestamps: list[float] = [] + + async def generate_and_push(self, prompt: str, dp_client: Any) -> None: + """Simulate generation + push directly to DataPlane.""" + self._call_count += 1 + call_idx = self._call_count + self._call_timestamps.append(time.monotonic()) + await asyncio.sleep(self._gen_latency_s) + group_id = f"group-{call_idx:04d}" + sample_id = f"{group_id}_g0" + await dp_client.put_samples.remote( + sample_ids=[sample_id], + partition_id="rollout_data", + fields=TensorDict( + { + "input_ids": torch.ones((1, 3), dtype=torch.long), + "prompt_ids_for_adv": torch.tensor( + [[self._call_count]], + dtype=torch.long, + ), + "total_reward": torch.tensor( + [float(self._call_count)], + dtype=torch.float32, + ), + "token_mask": torch.ones((1, 3), dtype=torch.float32), + "sample_mask": torch.ones(1, dtype=torch.float32), + }, + batch_size=[1], + ), + tags=[ + { + "group_id": group_id, + "weight_version": self._weight_version, + "committed": True, + "expected_num_samples": 1, + } + ], + ) + + def get_call_count(self) -> int: + return self._call_count + + def get_call_timestamps(self) -> list[float]: + return list(self._call_timestamps) + + def set_weight_version(self, version: int) -> None: + self._weight_version = version + + +@ray.remote(num_cpus=0) +class DryRunTrainer: + """Stub PolicyTrainerActor. + + Implements the same interface as production trainer: + train_from_meta(meta) → fetches from its own dp_client, sleeps, returns result + + Production ``PolicyTrainerActor`` owns its dp_client (built from + ``dp_cfg`` at construction). This stub mirrors that by binding the + dp_client handle at ``__init__`` time, not per call. + + Uses asyncio.sleep so event loop stays responsive — other pumps continue. + """ + + def __init__( + self, + dp_client: Any, + train_latency_s: float = 0.2, + expect_advantages: bool = False, + microbatch_latency_s: float = 0.0, + ): + self._dp_client = dp_client + self._train_latency_s = train_latency_s + self._expect_advantages = expect_advantages + self._microbatch_latency_s = microbatch_latency_s + self._trainer_version = 0 + self._train_count = 0 + self._train_start_times: list[float] = [] + self._last_advantages: torch.Tensor | None = None + # Split API state + self._open_step_id: str | None = None + self._microbatch_calls: list[tuple[str, list[str], float]] = [] + self._finish_calls: list[str] = [] + self._abort_calls: list[str] = [] + + async def begin_train_step( + self, + step_id: str, + loss_fn: Any = None, + gbs: int = 0, + mbs: int = 0, + ) -> None: + del loss_fn, gbs, mbs + if self._open_step_id is not None: + raise RuntimeError( + f"begin_train_step called while step {self._open_step_id} is open" + ) + self._open_step_id = step_id + + async def train_microbatch_from_meta(self, step_id: str, meta: KVBatchMeta) -> None: + if self._open_step_id is None: + raise RuntimeError("train_microbatch_from_meta called with no open step") + if step_id != self._open_step_id: + raise RuntimeError( + f"train_microbatch_from_meta step_id={step_id!r} != open {self._open_step_id!r}" + ) + now = time.monotonic() + self._microbatch_calls.append((step_id, list(meta.sample_ids), now)) + self._train_start_times.append(now) + if self._expect_advantages: + data = await self._dp_client.get_samples.remote( + sample_ids=meta.sample_ids, + partition_id=meta.partition_id, + select_fields=["input_ids", "advantages"], + ) + advantages = data["advantages"].detach().clone() + if self._last_advantages is None: + self._last_advantages = advantages + else: + self._last_advantages = torch.cat( + [self._last_advantages, advantages], dim=0 + ) + if self._microbatch_latency_s > 0: + await asyncio.sleep(self._microbatch_latency_s) + + async def finish_train_step(self, step_id: str) -> dict: + if self._open_step_id is None: + raise RuntimeError("finish_train_step called with no open step") + if step_id != self._open_step_id: + raise RuntimeError( + f"finish_train_step step_id={step_id!r} != open {self._open_step_id!r}" + ) + self._finish_calls.append(step_id) + self._open_step_id = None + self._trainer_version += 1 + self._train_count += 1 + return { + "loss": 1.0 / (self._trainer_version + 1), + "trainer_version": self._trainer_version, + } + + async def abort_train_step(self, step_id: str) -> None: + self._abort_calls.append(step_id) + self._open_step_id = None + + async def prepare_logprobs_from_meta(self, meta: KVBatchMeta) -> None: + del meta + return None + + def get_open_step_id(self) -> str | None: + return self._open_step_id + + def get_microbatch_calls(self) -> list[tuple[str, list[str], float]]: + return list(self._microbatch_calls) + + def get_finish_calls(self) -> list[str]: + return list(self._finish_calls) + + def get_abort_calls(self) -> list[str]: + return list(self._abort_calls) + + async def train_from_meta(self, meta: KVBatchMeta) -> dict: + """Simulate a training step.""" + self._train_start_times.append(time.monotonic()) + # Fetch records from DataPlane via the trainer's own client — + # same as production TQPolicy.train_from_meta. + select_fields = ["input_ids"] + if self._expect_advantages: + select_fields.append("advantages") + data = await self._dp_client.get_samples.remote( + sample_ids=meta.sample_ids, + partition_id=meta.partition_id, + select_fields=select_fields, + ) + if self._expect_advantages: + self._last_advantages = data["advantages"].detach().clone() + await asyncio.sleep(self._train_latency_s) + self._trainer_version += 1 + self._train_count += 1 + return { + "loss": 1.0 / (self._trainer_version + 1), + "trainer_version": self._trainer_version, + "clear_samples": True, + } + + def get_trainer_version(self) -> int: + return self._trainer_version + + def get_train_count(self) -> int: + return self._train_count + + def get_train_start_times(self) -> list[float]: + return list(self._train_start_times) + + def get_last_advantages(self) -> torch.Tensor | None: + return self._last_advantages + + +class DryRunAdvantageEstimator: + """Small estimator used by the dry-run SC advantage stage test.""" + + def compute_advantage( + self, + prompt_ids, + rewards, + mask, + repeated_batch, + **kwargs, + ): + del prompt_ids, repeated_batch, kwargs + centered = rewards - rewards.mean() + return centered.unsqueeze(-1).expand(mask.shape) + + +class DryRunWeightSynchronizer: + """Stub WeightSynchronizer — just sleeps. + + In production this would call WeightSynchronizer.sync_weights() which + dispatches to IPC/HTTP/NCCL based on deployment config. + """ + + def __init__(self, sync_latency_s: float = 0.05, gen_handle: Any = None): + self._sync_latency_s = sync_latency_s + self._gen_handle = gen_handle + self._sync_count = 0 + self._sync_timestamps: list[float] = [] + + async def sync_weights(self, trainer_version: int) -> None: + self._sync_count += 1 + self._sync_timestamps.append(time.monotonic()) + await asyncio.sleep(self._sync_latency_s) + if self._gen_handle is not None: + await self._gen_handle.set_weight_version.remote(trainer_version) + + +# ── pytest fixtures ─────────────────────────────────────────────────────── + + +@pytest.fixture(scope="module") +def ray_init(): + if not ray.is_initialized(): + ray.init(ignore_reinit_error=True, num_cpus=4) + yield + # Don't shutdown — other tests in the module may need Ray + + +def _meta_with_versions(versions: list[int]) -> KVBatchMeta: + sample_ids = [f"g{i}_g0" for i in range(len(versions))] + return KVBatchMeta( + partition_id="rollout_data", + task_name="train", + sample_ids=sample_ids, + tags=[ + { + "group_id": f"g{i}", + "weight_version": version, + "committed": True, + "expected_num_samples": 1, + } + for i, version in enumerate(versions) + ], + ) + + +# ── tests ───────────────────────────────────────────────────────────────── + + +class TestSingleControllerDryRun: + """Validate asyncio skeleton concurrency and backpressure.""" + + def _make_controller( + self, + dp_client, + gen, + trainer, + weight_sync=None, + max_train_steps=3, + max_rollout_prompts=12, + min_prompt_groups_per_batch=1, + generations_per_prompt=1, + max_buffered_rollouts=4, + max_inflight_prompts=4, + max_weight_staleness_versions=1, + advantage_enabled=False, + advantage_estimator=None, + diagnostics=False, + ): + cfg = SingleControllerConfig( + max_train_steps=max_train_steps, + max_rollout_prompts=max_rollout_prompts, + min_prompt_groups_per_batch=min_prompt_groups_per_batch, + generations_per_prompt=generations_per_prompt, + max_buffered_rollouts=max_buffered_rollouts, + max_inflight_prompts=max_inflight_prompts, + max_weight_staleness_versions=max_weight_staleness_versions, + advantage_enabled=advantage_enabled, + diagnostics=diagnostics, + ) + if weight_sync is None: + weight_sync = DryRunWeightSynchronizer(gen_handle=gen) + prompts = [f"prompt_{i}" for i in range(10)] + return SingleControllerActor.remote( + cfg, + prompts, + dp_client, + gen, + trainer, + weight_sync, + advantage_estimator, + ) + + def test_dry_run_completes(self, ray_init): + """SC completes N train steps without deadlock on CPU.""" + dp_client = FakeDataPlaneActor.remote() + gen = DryRunGenWorker.remote(gen_latency_s=0.05) + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.1) + weight_sync = DryRunWeightSynchronizer(sync_latency_s=0.02, gen_handle=gen) + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + weight_sync, + max_train_steps=3, + max_rollout_prompts=12, + min_prompt_groups_per_batch=1, + generations_per_prompt=1, + ) + + result = ray.get(ctrl.run.remote(), timeout=30) + assert result["train_steps"] == 3 + assert result["trainer_version"] == 3 + + def test_advantage_pump_writes_advantages_before_train(self, ray_init): + """SC computes advantages from DataPlane inputs and writes them back.""" + dp_client = FakeDataPlaneActor.remote() + gen = DryRunGenWorker.remote(gen_latency_s=0.01) + trainer = DryRunTrainer.remote( + dp_client, + train_latency_s=0.01, + expect_advantages=True, + ) + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + max_train_steps=1, + max_rollout_prompts=2, + min_prompt_groups_per_batch=2, + generations_per_prompt=1, + advantage_enabled=True, + advantage_estimator=DryRunAdvantageEstimator(), + ) + + result = ray.get(ctrl.run.remote(), timeout=30) + assert result["train_steps"] == 1 + + advantages = ray.get(trainer.get_last_advantages.remote()) + assert advantages is not None + # Per-group dispatch: each group is one sample → centered advantage is 0. + # The two microbatch calls are concatenated. + assert advantages.shape == (2, 3) + assert torch.allclose(advantages, torch.zeros((2, 3))) + + def test_rollout_pump_runs_concurrently_with_train(self, ray_init): + """rollout_pump dispatches while train_pump is sleeping. + + If pumps were sequential, rollout dispatches would only happen + between training steps. With concurrent asyncio tasks, rollout + dispatches happen while trainer is in asyncio.sleep(). + """ + dp_client = FakeDataPlaneActor.remote() + # Gen is fast (0.02s), trainer is slow (0.3s) + gen = DryRunGenWorker.remote(gen_latency_s=0.02) + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.3) + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + max_train_steps=2, + max_rollout_prompts=10, + min_prompt_groups_per_batch=1, + generations_per_prompt=1, + max_buffered_rollouts=6, + max_inflight_prompts=6, + ) + + ray.get(ctrl.run.remote(), timeout=30) + + # Multiple rollouts should have completed during the first train step + call_timestamps = ray.get(gen.get_call_timestamps.remote()) + train_start_times = ray.get(trainer.get_train_start_times.remote()) + + assert len(call_timestamps) > 0 + assert len(train_start_times) > 0 + + # Some rollout calls should have started AFTER the first train step began + first_train_start = train_start_times[0] + rollouts_during_train = sum(1 for t in call_timestamps if t > first_train_start) + assert rollouts_during_train > 0, ( + "No rollouts dispatched while trainer was running — pumps may not be concurrent" + ) + + def test_buffer_capacity_semaphore_blocks_rollout(self, ray_init): + """_rollout_pump blocks when buffer capacity is exhausted. + + Set max_buffered_rollouts=2 with slow trainer — rollout_pump + should fill buffer capacity then block until trainer clears a group. + """ + dp_client = FakeDataPlaneActor.remote() + gen = DryRunGenWorker.remote(gen_latency_s=0.01) # fast gen + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.3) # slow trainer + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + max_train_steps=2, + max_rollout_prompts=8, + min_prompt_groups_per_batch=1, + generations_per_prompt=1, + max_buffered_rollouts=2, # small buffer — backpressure kicks in + max_inflight_prompts=4, + ) + + start = time.monotonic() + result = ray.get(ctrl.run.remote(), timeout=30) + elapsed = time.monotonic() - start + + # Should complete without deadlock + assert result["train_steps"] == 2 + # DataPlane depth should never exceed max_buffered_rollouts (approx) + # We can't easily observe mid-run depth, but completion = no deadlock + + def test_rollout_permitted_pauses_during_sync(self, ray_init): + """_rollout_pump pauses new dispatches during _sync_weights. + + During weight sync, _rollout_permitted is cleared. _rollout_pump + blocks on _rollout_permitted.wait() so no new generate_and_push + calls are made. Existing in-flight ones drain naturally. + """ + dp_client = FakeDataPlaneActor.remote() + gen = DryRunGenWorker.remote(gen_latency_s=0.05) + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.05) + weight_sync = DryRunWeightSynchronizer( + sync_latency_s=0.15, + gen_handle=gen, + ) # slow sync + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + weight_sync, + max_train_steps=2, + max_rollout_prompts=8, + min_prompt_groups_per_batch=1, + generations_per_prompt=1, + ) + + result = ray.get(ctrl.run.remote(), timeout=30) + assert result["train_steps"] == 2 + # Weight sync happened (sync_count > 0 implies gate opened correctly) + + def test_ping_returns_while_running(self, ray_init): + """ping() returns immediately if event loop is running — basis for watchdog.""" + dp_client = FakeDataPlaneActor.remote() + gen = DryRunGenWorker.remote(gen_latency_s=0.05) + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.1) + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + max_train_steps=5, + max_rollout_prompts=20, + min_prompt_groups_per_batch=1, + generations_per_prompt=1, + ) + + # Start SC + run_ref = ctrl.run.remote() + + # Ping while SC is running — should return quickly + time.sleep(0.2) + ping_start = time.monotonic() + health = ray.get(ctrl.ping.remote(), timeout=5) + ping_elapsed = time.monotonic() - ping_start + + assert health["alive"] is True + assert ping_elapsed < 3.0, ( + f"ping() took {ping_elapsed:.2f}s — event loop may be blocked" + ) + + ray.get(run_ref, timeout=30) + + def test_staleness_sampler_filters_correctly(self): + """StalenessSampler returns freshest complete groups within the window.""" + sampler = StalenessSampler(max_staleness_versions=2) + + meta = _meta_with_versions([3, 4, 5, 2, 6]) + + indices = sampler.select_indices( + meta, + trainer_version=5, + min_prompt_groups=2, + generations_per_prompt=1, + ) + assert indices == [2, 1] + + def test_staleness_sampler_returns_none_when_insufficient(self): + """StalenessSampler returns None when not enough eligible rows.""" + sampler = StalenessSampler(max_staleness_versions=1) + meta = _meta_with_versions([1]) + result = sampler.select_indices( + meta, + trainer_version=5, + min_prompt_groups=2, + generations_per_prompt=1, + ) + assert result is None + + def test_staleness_sampler_requires_complete_prompt_groups(self): + """Staleness sampler skips incomplete prompt groups.""" + sampler = StalenessSampler(max_staleness_versions=2) + meta = KVBatchMeta( + partition_id="rollout_data", + task_name="train", + sample_ids=["p0_g0", "p1_g0", "p1_g1"], + tags=[ + {"group_id": "p0", "weight_version": 5, "expected_num_samples": 2}, + {"group_id": "p1", "weight_version": 5, "expected_num_samples": 2}, + {"group_id": "p1", "weight_version": 5, "expected_num_samples": 2}, + ], + ) + + assert sampler.select_indices( + meta, + trainer_version=5, + min_prompt_groups=1, + generations_per_prompt=2, + ) == [1, 2] + + def test_strict_on_policy_batch_sampler_requires_exact_version(self): + """Strict sampler waits for a full batch at the trainer version.""" + sampler = StalenessSampler(max_staleness_versions=0) + meta = _meta_with_versions([4, 5, 5, 6]) + + assert ( + sampler.select_indices( + meta, + trainer_version=5, + min_prompt_groups=3, + generations_per_prompt=1, + ) + is None + ) + assert sampler.select_indices( + meta, + trainer_version=5, + min_prompt_groups=2, + generations_per_prompt=1, + ) == [1, 2] + + def test_strict_on_policy_batch_sampler_evicts_old_groups(self): + """Strict sampler marks complete old-version groups for eviction.""" + sampler = StalenessSampler(max_staleness_versions=0) + meta = _meta_with_versions([4, 5, 4]) + + assert sampler.evictable_indices( + meta, + trainer_version=5, + generations_per_prompt=1, + ) == [0, 2] + + +@ray.remote(num_cpus=0) +class _ReapInFlightHelperActor: + """Tiny Ray actor exposing SingleControllerActor._reap_in_flight_nonblocking.""" + + async def reap(self, refs): + if not refs: + return [] + ref_to_task = {ref: asyncio.ensure_future(ref) for ref in refs} + await asyncio.wait(ref_to_task.values(), timeout=0.05) + pending = [] + for ref, task in ref_to_task.items(): + if task.done(): + task.result() + else: + task.cancel() + pending.append(ref) + return pending + + +@ray.remote +def _sleep_then_return(seconds: float, value: int = 0) -> int: + time.sleep(seconds) + return value + + +@ray.remote +def _raise_after(seconds: float) -> None: + time.sleep(seconds) + raise RuntimeError("boom") + + +class TestReapInFlightNonblocking: + """Validate _reap_in_flight_nonblocking helper semantics.""" + + def test_reap_empty_list_returns_empty(self, ray_init): + helper = _ReapInFlightHelperActor.remote() + result = ray.get(helper.reap.remote([])) + assert result == [] + + def test_reap_drains_completed_and_returns_pending(self, ray_init): + helper = _ReapInFlightHelperActor.remote() + # One finishes immediately, two stay pending + done_ref = _sleep_then_return.remote(0.0, 1) + pending1 = _sleep_then_return.remote(10.0, 2) + pending2 = _sleep_then_return.remote(10.0, 3) + # Give Ray a moment to mark done_ref as ready + time.sleep(0.5) + result = ray.get(helper.reap.remote([done_ref, pending1, pending2])) + # Only the still-pending refs are returned + assert len(result) == 2 + result_set = {r.hex() for r in result} + assert pending1.hex() in result_set + assert pending2.hex() in result_set + + def test_reap_surfaces_exception_from_completed(self, ray_init): + helper = _ReapInFlightHelperActor.remote() + bad_ref = _raise_after.remote(0.0) + time.sleep(0.5) + with pytest.raises(Exception): + ray.get(helper.reap.remote([bad_ref])) + + +class TestDryRunTrainerSplitAPI: + """Smoke test for DryRunTrainer split-API methods.""" + + def test_drytrainer_split_api_smoke(self, ray_init): + dp_client = FakeDataPlaneActor.remote() + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + meta = KVBatchMeta( + partition_id="rollout_data", + task_name="train", + sample_ids=["a", "b"], + ) + # Open step, microbatch, finish + ray.get(trainer.begin_train_step.remote("step-1")) + ray.get(trainer.train_microbatch_from_meta.remote("step-1", meta)) + ray.get(trainer.train_microbatch_from_meta.remote("step-1", meta)) + result = ray.get(trainer.finish_train_step.remote("step-1")) + assert result["trainer_version"] == 1 + assert ray.get(trainer.get_open_step_id.remote()) is None + assert ray.get(trainer.get_finish_calls.remote()) == ["step-1"] + mbs = ray.get(trainer.get_microbatch_calls.remote()) + assert len(mbs) == 2 + assert all(call[0] == "step-1" for call in mbs) + assert all(call[1] == ["a", "b"] for call in mbs) + # Abort then begin again + ray.get(trainer.begin_train_step.remote("step-2")) + ray.get(trainer.train_microbatch_from_meta.remote("step-2", meta)) + ray.get(trainer.abort_train_step.remote("step-2")) + assert ray.get(trainer.get_open_step_id.remote()) is None + assert ray.get(trainer.get_abort_calls.remote()) == ["step-2"] + # Trainer version did not advance via abort + ray.get(trainer.begin_train_step.remote("step-3")) + ray.get(trainer.finish_train_step.remote("step-3")) + # Now begin while a step is open should raise + ray.get(trainer.begin_train_step.remote("step-4")) + with pytest.raises(Exception): + ray.get(trainer.begin_train_step.remote("step-5")) + + +@ray.remote(num_cpus=0) +class StaggeredGenWorker: + """Gen worker that reads latency and group label from the prompt. + + Prompt format: ``"{idx}:{latency}"``. Sleeps for ``latency`` then + pushes a row with ``group_id="group-{idx}"``. + """ + + def __init__(self, weight_version: int = 0) -> None: + self._weight_version = weight_version + self._completion_timestamps: list[float] = [] + + async def generate_and_push(self, prompt: str, dp_client: Any) -> None: + idx_str, latency_str = prompt.split(":") + idx = int(idx_str) + latency = float(latency_str) + await asyncio.sleep(latency) + group_id = f"group-{idx:04d}" + sample_id = f"{group_id}_g0" + await dp_client.put_samples.remote( + sample_ids=[sample_id], + partition_id="rollout_data", + fields=TensorDict( + { + "input_ids": torch.ones((1, 3), dtype=torch.long), + }, + batch_size=[1], + ), + tags=[ + { + "group_id": group_id, + "weight_version": self._weight_version, + "committed": True, + "expected_num_samples": 1, + } + ], + ) + self._completion_timestamps.append(time.monotonic()) + + def get_completion_timestamps(self) -> list[float]: + return list(self._completion_timestamps) + + def set_weight_version(self, version: int) -> None: + self._weight_version = version + + +class TestStreamingTrainPump: + """Streaming train_pump end-to-end behavior under DryRunTrainer.""" + + def _make_controller( + self, + dp_client, + gen, + trainer, + prompts: list[str], + weight_sync=None, + max_train_steps=1, + max_rollout_prompts=4, + min_prompt_groups_per_batch=1, + target_prompt_groups_per_step=4, + generations_per_prompt=1, + max_buffered_rollouts=8, + max_inflight_prompts=8, + max_weight_staleness_versions=1, + batch_selection_strategy="staleness_window", + ): + cfg = SingleControllerConfig( + max_train_steps=max_train_steps, + max_rollout_prompts=max_rollout_prompts, + min_prompt_groups_per_batch=min_prompt_groups_per_batch, + target_prompt_groups_per_step=target_prompt_groups_per_step, + generations_per_prompt=generations_per_prompt, + max_buffered_rollouts=max_buffered_rollouts, + max_inflight_prompts=max_inflight_prompts, + max_weight_staleness_versions=max_weight_staleness_versions, + batch_selection_strategy=batch_selection_strategy, + ) + if weight_sync is None: + weight_sync = DryRunWeightSynchronizer(gen_handle=gen) + return SingleControllerActor.remote( + cfg, + prompts if prompts else ["unused"], + dp_client, + gen, + trainer, + weight_sync, + None, + ) + + def test_streaming_dispatches_in_arrival_order(self, ray_init): + """SC dispatches train_microbatch in order groups commit at DP.""" + dp_client = FakeDataPlaneActor.remote() + # Group 0 slow, group 1 fast, group 2 medium → arrival order: 1, 2, 0 + gen = StaggeredGenWorker.remote() + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + prompts = ["0:0.30", "1:0.05", "2:0.15"] + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + prompts=prompts, + max_train_steps=1, + max_rollout_prompts=3, + target_prompt_groups_per_step=3, + min_prompt_groups_per_batch=1, + ) + result = ray.get(ctrl.run.remote(), timeout=60) + assert result["train_steps"] == 1 + mbs = ray.get(trainer.get_microbatch_calls.remote()) + # 3 microbatches dispatched + assert len(mbs) == 3 + dispatched_groups = [call[1][0].split("_")[0] for call in mbs] + # group-0001 (fastest) before group-0002 (medium) before group-0000 (slow) + assert dispatched_groups == ["group-0001", "group-0002", "group-0000"] + + def test_trainer_version_advances_only_at_finish(self, ray_init): + """trainer_version stays put across mb calls; ticks on finish.""" + dp_client = FakeDataPlaneActor.remote() + gen = StaggeredGenWorker.remote() + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + prompts = [f"{i}:0.02" for i in range(4)] + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + prompts=prompts, + max_train_steps=1, + max_rollout_prompts=4, + target_prompt_groups_per_step=4, + min_prompt_groups_per_batch=1, + ) + result = ray.get(ctrl.run.remote(), timeout=60) + assert result["train_steps"] == 1 + # trainer_version should be 1 (one finish_train_step call) + assert ray.get(trainer.get_trainer_version.remote()) == 1 + # finish was called exactly once + finishes = ray.get(trainer.get_finish_calls.remote()) + assert finishes == ["sc-step-000000"] + mbs = ray.get(trainer.get_microbatch_calls.remote()) + assert len(mbs) == 4 + + def test_strict_on_policy_rejects_stale_group_midstep(self, ray_init): + """Strict mode (staleness=0): group at version V-1 is not dispatched.""" + dp_client = FakeDataPlaneActor.remote() + # Pre-stage: stale group at version -1 (trainer starts at v=0, strict) + stale_meta = ray.get( + dp_client.put_samples.remote( + sample_ids=["stale_g0"], + partition_id="rollout_data", + fields=TensorDict( + {"input_ids": torch.ones((1, 3), dtype=torch.long)}, + batch_size=[1], + ), + tags=[ + { + "group_id": "stale", + "weight_version": -1, + "committed": True, + "expected_num_samples": 1, + } + ], + ) + ) + del stale_meta + gen = StaggeredGenWorker.remote(weight_version=0) + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + prompts = [f"{i}:0.02" for i in range(2)] + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + prompts=prompts, + max_train_steps=1, + max_rollout_prompts=2, + target_prompt_groups_per_step=2, + min_prompt_groups_per_batch=1, + batch_selection_strategy="strict_on_policy", + max_weight_staleness_versions=0, + ) + result = ray.get(ctrl.run.remote(), timeout=60) + assert result["train_steps"] == 1 + mbs = ray.get(trainer.get_microbatch_calls.remote()) + # The stale group was evicted by _evict_stale_claimed; never dispatched + all_sample_ids = [sid for _, ids, _ in mbs for sid in ids] + assert "stale_g0" not in all_sample_ids + + def test_long_tail_overlap(self, ray_init): + """First microbatch begins before the long-tail group's rollout finishes.""" + dp_client = FakeDataPlaneActor.remote() + # Group 0 fast, 1-3 medium, group 4 slow + gen = StaggeredGenWorker.remote() + trainer = DryRunTrainer.remote( + dp_client, train_latency_s=0.0, microbatch_latency_s=0.0 + ) + prompts = ["0:0.01", "1:0.03", "2:0.03", "3:0.03", "4:0.30"] + + ctrl = self._make_controller( + dp_client, + gen, + trainer, + prompts=prompts, + max_train_steps=1, + max_rollout_prompts=5, + target_prompt_groups_per_step=5, + min_prompt_groups_per_batch=1, + ) + result = ray.get(ctrl.run.remote(), timeout=60) + assert result["train_steps"] == 1 + mbs = ray.get(trainer.get_microbatch_calls.remote()) + assert len(mbs) == 5 + first_mb_ts = mbs[0][2] + completion_ts = ray.get(gen.get_completion_timestamps.remote()) + # 5 completions; the slow group is the last one to finish + slow_completion = max(completion_ts) + assert first_mb_ts < slow_completion, ( + f"first mb dispatched at {first_mb_ts} but slow group " + f"completed at {slow_completion}" + ) + + def test_abort_train_step_idempotent_and_clears_state(self, ray_init): + """abort_train_step clears state and a new begin succeeds.""" + dp_client = FakeDataPlaneActor.remote() + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + meta = KVBatchMeta( + partition_id="rollout_data", + task_name="train", + sample_ids=["a", "b"], + ) + ray.get(trainer.begin_train_step.remote("step-x")) + ray.get(trainer.train_microbatch_from_meta.remote("step-x", meta)) + ray.get(trainer.train_microbatch_from_meta.remote("step-x", meta)) + ray.get(trainer.abort_train_step.remote("step-x")) + assert ray.get(trainer.get_open_step_id.remote()) is None + # New begin must succeed + ray.get(trainer.begin_train_step.remote("step-y")) + assert ray.get(trainer.get_open_step_id.remote()) == "step-y" + # Idempotent: a second abort on a closed step also clears (no raise) + ray.get(trainer.abort_train_step.remote("step-y")) + assert ray.get(trainer.get_open_step_id.remote()) is None + ray.get(trainer.abort_train_step.remote("step-y")) + assert ray.get(trainer.get_open_step_id.remote()) is None + + def test_empty_step_is_no_op(self, ray_init): + """No rollouts → SC exits without calling finish_train_step.""" + dp_client = FakeDataPlaneActor.remote() + gen = StaggeredGenWorker.remote() + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + ctrl = self._make_controller( + dp_client, + gen, + trainer, + prompts=["0:0.01"], + max_train_steps=1, + max_rollout_prompts=0, + target_prompt_groups_per_step=2, + min_prompt_groups_per_batch=1, + ) + result = ray.get(ctrl.run.remote(), timeout=30) + assert result["train_steps"] == 0 + assert ray.get(trainer.get_finish_calls.remote()) == [] + assert ray.get(trainer.get_microbatch_calls.remote()) == [] + + def test_clear_samples_called_once_per_step(self, ray_init): + """clear_samples is called exactly once per step covering all dispatched ids.""" + dp_client = FakeDataPlaneActor.remote() + gen = StaggeredGenWorker.remote() + trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) + prompts = ["0:0.01", "1:0.02", "2:0.03"] + ctrl = self._make_controller( + dp_client, + gen, + trainer, + prompts=prompts, + max_train_steps=1, + max_rollout_prompts=3, + target_prompt_groups_per_step=3, + min_prompt_groups_per_batch=1, + ) + result = ray.get(ctrl.run.remote(), timeout=60) + assert result["train_steps"] == 1 + clear_calls = ray.get(dp_client.get_clear_calls.remote()) + assert len(clear_calls) == 1 + mbs = ray.get(trainer.get_microbatch_calls.remote()) + dispatched_ids = set() + for _, ids, _ in mbs: + dispatched_ids.update(ids) + assert set(clear_calls[0]) == dispatched_ids + + +class TestRisk06EventLoopBlocking: + """RISK-06: validate that asyncio event loop is not blocked during training. + + The risk: if train_from_meta is a synchronous blocking call, the asyncio + event loop freezes and _rollout_pump + _sync_weights can't make progress. + Fix: use `await loop.run_in_executor(None, blocking_fn, ...)` or ensure + train_from_meta is an async method (as DryRunTrainer is). + + These tests document the expected behavior and serve as a benchmark. + """ + + def test_blocking_call_freezes_loop(self): + """Demonstrate that a synchronous time.sleep freezes the event loop. + + This test validates the PROBLEM (not the solution) — if train used + time.sleep instead of asyncio.sleep, other tasks would not progress. + """ + progress: list[str] = [] + + async def blocking_task(): + progress.append("blocking_start") + time.sleep(0.1) # blocks event loop + progress.append("blocking_end") + + async def concurrent_task(): + progress.append("concurrent_start") + await asyncio.sleep(0) + progress.append("concurrent_mid") + await asyncio.sleep(0) + progress.append("concurrent_end") + + async def run(): + t1 = asyncio.create_task(blocking_task()) + t2 = asyncio.create_task(concurrent_task()) + await asyncio.gather(t1, t2) + + asyncio.run(run()) + + # With blocking call, concurrent task can't interleave during the sleep + # blocking_start, blocking_end happen before concurrent_mid + block_end_idx = progress.index("blocking_end") + concurrent_mid_idx = progress.index("concurrent_mid") + assert block_end_idx < concurrent_mid_idx, ( + "blocking_task did not freeze concurrent_task as expected" + ) + + def test_async_sleep_allows_concurrency(self): + """Demonstrate that asyncio.sleep yields to other tasks. + + The DryRunTrainer uses asyncio.sleep — this shows the event loop + stays responsive during 'training'. Production code must use + loop.run_in_executor() for real blocking GPU operations. + """ + progress: list[str] = [] + + async def async_task(): + progress.append("async_start") + await asyncio.sleep(0.1) # yields to event loop + progress.append("async_end") + + async def concurrent_task(): + progress.append("concurrent_start") + await asyncio.sleep(0.01) + progress.append("concurrent_mid") + await asyncio.sleep(0) + progress.append("concurrent_end") + + async def run(): + t1 = asyncio.create_task(async_task()) + t2 = asyncio.create_task(concurrent_task()) + await asyncio.gather(t1, t2) + + asyncio.run(run()) + + # concurrent_task should make progress while async_task is sleeping + async_end_idx = progress.index("async_end") + concurrent_mid_idx = progress.index("concurrent_mid") + assert concurrent_mid_idx < async_end_idx, ( + "concurrent_task should have progressed while async_task was sleeping" + ) + + def test_run_in_executor_unblocks_loop(self): + """Validate the production fix for RISK-06. + + In production, policy.train() is a blocking GPU call. SC must use: + await loop.run_in_executor(None, policy.train, ...) + This runs the blocking call in a thread pool, leaving the event loop + free for _rollout_pump and _sync_weights to make progress. + """ + progress: list[str] = [] + + def blocking_train(): + time.sleep(0.1) + return "trained" + + async def train_with_executor(): + loop = asyncio.get_running_loop() + progress.append("train_start") + result = await loop.run_in_executor(None, blocking_train) + progress.append("train_end") + return result + + async def rollout(): + progress.append("rollout_start") + await asyncio.sleep(0.02) + progress.append("rollout_mid") + await asyncio.sleep(0.02) + progress.append("rollout_end") + + async def run(): + t1 = asyncio.create_task(train_with_executor()) + t2 = asyncio.create_task(rollout()) + await asyncio.gather(t1, t2) + + asyncio.run(run()) + + # rollout should have made progress WHILE train was blocking in executor + train_end_idx = progress.index("train_end") + rollout_mid_idx = progress.index("rollout_mid") + assert rollout_mid_idx < train_end_idx, ( + "rollout should have progressed while blocking_train ran in executor" + ) diff --git a/tests/unit/algorithms/test_staleness_sampler.py b/tests/unit/algorithms/test_staleness_sampler.py new file mode 100644 index 00000000000..436dd122cf9 --- /dev/null +++ b/tests/unit/algorithms/test_staleness_sampler.py @@ -0,0 +1,177 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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 StalenessSampler (focusing on select_one_group).""" + +from __future__ import annotations + +from typing import Any + +from nemo_rl.algorithms.staleness_sampler import StalenessSampler +from nemo_rl.data_plane import KVBatchMeta + + +def _meta_with_groups( + groups: list[dict[str, Any]], +) -> KVBatchMeta: + """Build a KVBatchMeta from a list of group specs. + + Each group dict has keys: group_id, weight_version, committed (default True), + expected_num_samples, num_samples (default = expected_num_samples). + """ + sample_ids: list[str] = [] + tags: list[dict[str, Any]] = [] + for g in groups: + gid = g["group_id"] + expected = g["expected_num_samples"] + n = g.get("num_samples", expected) + for i in range(n): + sample_ids.append(f"{gid}_g{i}") + tags.append( + { + "group_id": gid, + "weight_version": g["weight_version"], + "committed": g.get("committed", True), + "expected_num_samples": expected, + } + ) + return KVBatchMeta( + partition_id="rollout_data", + task_name="train", + sample_ids=sample_ids, + tags=tags, + ) + + +def test_select_one_group_returns_none_on_empty_meta(): + sampler = StalenessSampler(max_staleness_versions=2) + meta = KVBatchMeta( + partition_id="rollout_data", + task_name="train", + sample_ids=[], + tags=[], + ) + assert ( + sampler.select_one_group(meta, trainer_version=5, generations_per_prompt=1) + is None + ) + + +def test_select_one_group_returns_only_complete_group(): + sampler = StalenessSampler(max_staleness_versions=2) + meta = _meta_with_groups( + [ + {"group_id": "g0", "weight_version": 5, "expected_num_samples": 1}, + ] + ) + assert sampler.select_one_group( + meta, trainer_version=5, generations_per_prompt=1 + ) == [0] + + +def test_select_one_group_picks_lowest_lag_first(): + sampler = StalenessSampler(max_staleness_versions=3) + meta = _meta_with_groups( + [ + {"group_id": "g0", "weight_version": 3, "expected_num_samples": 1}, + {"group_id": "g1", "weight_version": 5, "expected_num_samples": 1}, + {"group_id": "g2", "weight_version": 4, "expected_num_samples": 1}, + ] + ) + # trainer=5: g0 lag=2, g1 lag=0, g2 lag=1 → picks g1 (index 1) + assert sampler.select_one_group( + meta, trainer_version=5, generations_per_prompt=1 + ) == [1] + + +def test_select_one_group_tiebreak_leftmost_wins(): + sampler = StalenessSampler(max_staleness_versions=2) + meta = _meta_with_groups( + [ + {"group_id": "g0", "weight_version": 4, "expected_num_samples": 2}, + {"group_id": "g1", "weight_version": 4, "expected_num_samples": 2}, + ] + ) + # Both lag=1. Tiebreak: leftmost indices[0]. g0 occupies [0,1], g1 [2,3] + assert sampler.select_one_group( + meta, trainer_version=5, generations_per_prompt=2 + ) == [0, 1] + + +def test_select_one_group_skips_incomplete_and_uncommitted(): + sampler = StalenessSampler(max_staleness_versions=2) + meta = _meta_with_groups( + [ + # Incomplete group: expected 2, only 1 sample + { + "group_id": "g0", + "weight_version": 5, + "expected_num_samples": 2, + "num_samples": 1, + }, + # Uncommitted group + { + "group_id": "g1", + "weight_version": 5, + "expected_num_samples": 1, + "committed": False, + }, + # Eligible group + {"group_id": "g2", "weight_version": 5, "expected_num_samples": 1}, + ] + ) + # g0 occupies idx 0; g1 idx 1; g2 idx 2 → picks g2 + assert sampler.select_one_group( + meta, trainer_version=5, generations_per_prompt=1 + ) == [2] + + +def test_select_one_group_rejects_future_version(): + sampler = StalenessSampler(max_staleness_versions=5) + meta = _meta_with_groups( + [ + {"group_id": "g0", "weight_version": 6, "expected_num_samples": 1}, + {"group_id": "g1", "weight_version": 4, "expected_num_samples": 1}, + ] + ) + # trainer=5: g0 has weight_version > trainer_version, rejected; g1 lag=1 + assert sampler.select_one_group( + meta, trainer_version=5, generations_per_prompt=1 + ) == [1] + + +def test_select_one_group_strict_on_policy(): + sampler = StalenessSampler(max_staleness_versions=0) + meta = _meta_with_groups( + [ + {"group_id": "g0", "weight_version": 4, "expected_num_samples": 1}, + {"group_id": "g1", "weight_version": 5, "expected_num_samples": 1}, + ] + ) + # strict: only weight_version==trainer_version eligible + assert sampler.select_one_group( + meta, trainer_version=5, generations_per_prompt=1 + ) == [1] + # All stale → None + meta_stale = _meta_with_groups( + [ + {"group_id": "g0", "weight_version": 4, "expected_num_samples": 1}, + ] + ) + assert ( + sampler.select_one_group( + meta_stale, trainer_version=5, generations_per_prompt=1 + ) + is None + ) diff --git a/tests/unit/data_plane/test_kvbatchmeta.py b/tests/unit/data_plane/test_kvbatchmeta.py index 4774c44f1e3..a8dc3bc822d 100644 --- a/tests/unit/data_plane/test_kvbatchmeta.py +++ b/tests/unit/data_plane/test_kvbatchmeta.py @@ -147,6 +147,96 @@ def test_tags_travel_with_subset_slice_concat(): assert joined.tags == m.tags +def test_drop_removes_indices_and_keeps_remaining_rows(): + """Rows at ``indices`` disappear; survivors keep their tags/seqlens.""" + m = KVBatchMeta( + partition_id="p", + task_name="t", + sample_ids=["a", "b", "c", "d"], + sequence_lengths=[1, 2, 3, 4], + tags=[{"i": 0}, {"i": 1}, {"i": 2}, {"i": 3}], + ) + remaining = m.drop([1, 3]) + assert remaining.sample_ids == ["a", "c"] + assert remaining.sequence_lengths == [1, 3] + assert remaining.tags == [{"i": 0}, {"i": 2}] + + +def test_drop_empty_indices_returns_identical_content(): + """``drop([])`` returns a fresh copy with the same rows.""" + m = KVBatchMeta( + partition_id="p", + task_name="t", + sample_ids=["a", "b"], + sequence_lengths=[1, 2], + ) + out = m.drop([]) + assert out.sample_ids == m.sample_ids + assert out.sequence_lengths == m.sequence_lengths + assert out is not m + + +def test_drop_all_returns_none(): + """Dropping every row returns ``None`` (callers chain into ``is None`` branches).""" + m = KVBatchMeta( + partition_id="p", + task_name="t", + sample_ids=["a", "b"], + tags=[{"i": 0}, {"i": 1}], + ) + assert m.drop([0, 1]) is None + + +def test_drop_indices_can_be_unordered_or_duplicated(): + """Duplicate / out-of-order indices collapse via the internal set.""" + m = KVBatchMeta( + partition_id="p", + task_name="t", + sample_ids=["a", "b", "c"], + ) + assert m.drop([2, 0, 0]).sample_ids == ["b"] + + +def test_with_fields_appends_and_dedupes_preserving_order(): + """Merges into ``fields`` with order-preserving dedup.""" + m = KVBatchMeta( + partition_id="p", + task_name="t", + sample_ids=["a"], + fields=["input_ids", "advantages"], + ) + out = m.with_fields(["advantages", "logprobs"]) + assert out.fields == ["input_ids", "advantages", "logprobs"] + + +def test_with_fields_initializes_from_none(): + """Seeds ``fields`` from the argument when previously ``None``.""" + m = KVBatchMeta(partition_id="p", task_name="t", sample_ids=["a"]) + out = m.with_fields(["x", "y", "x"]) + assert out.fields == ["x", "y"] + + +def test_with_fields_returns_independent_copy(): + """Returned meta does not share mutable references with the source.""" + m = KVBatchMeta( + partition_id="p", + task_name="t", + sample_ids=["a", "b"], + sequence_lengths=[1, 2], + extra_info={"step": 0}, + tags=[{"x": 1}, {"x": 2}], + ) + out = m.with_fields(["z"]) + out.sample_ids.append("c") + out.sequence_lengths.append(3) # type: ignore[union-attr] + out.extra_info["step"] = 99 + out.tags[0]["x"] = 999 # type: ignore[index] + assert m.sample_ids == ["a", "b"] + assert m.sequence_lengths == [1, 2] + assert m.extra_info == {"step": 0} + assert m.tags == [{"x": 1}, {"x": 2}] + + def test_tags_none_when_either_side_missing_in_concat(): """``concat`` drops tags if either side has none — symmetric with the ``sequence_lengths`` behavior.""" diff --git a/tests/unit/models/policy/test_megatron_split_state.py b/tests/unit/models/policy/test_megatron_split_state.py new file mode 100644 index 00000000000..fb50c839ef7 --- /dev/null +++ b/tests/unit/models/policy/test_megatron_split_state.py @@ -0,0 +1,638 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""CPU state-machine tests for MegatronPolicyWorkerImpl's split-API. + +These tests cover the lifecycle and call-order invariants — they do NOT +exercise real distributed comms, the mcore scheduler, or the optimizer. +Numerical equivalence vs sync ``train()`` lives in the GPU parity tests. + +The bugs these catch: + - silent gradient over-counting if ``model.no_sync()`` is not wrapped + around ``megatron_forward_backward`` (the mcore DDP hooks would + dispatch a per-call reduce, ADDING to an already-reduced bucket). + - PP>1 pipeline-schedule bypass if ``model.config.grad_sync_func`` is + not nulled for the step's duration. + - ``trainer_version`` advancing on abort. + - ``zero_grad_buffer`` not called at begin (mcore's contiguous grad + buffer leaks stale grads otherwise). + - off-by-one in ``total_num_microbatches`` (used to scale MoE aux-loss). +""" + +from __future__ import annotations + +from unittest.mock import MagicMock, patch + +import pytest +import torch + +# megatron.bridge is only available with the mcore extras. Without it the +# eager import of megatron_policy_worker (transitively imports megatron.bridge) +# fails at COLLECTION time on non-mcore shards, which then breaks every other +# test in that shard. importorskip stops collection cleanly here. +pytest.importorskip("megatron.bridge") + +# Eagerly import the worker module so ``unittest.mock.patch`` can resolve +# attributes on it via ``getattr``. Without this the patch path +# ``nemo_rl.models.policy.workers.megatron_policy_worker.`` fails +# at ``getattr(workers, "megatron_policy_worker")``. +import nemo_rl.models.policy.workers.megatron_policy_worker # noqa: E402,F401 + +pytestmark = pytest.mark.mcore + +# Module path of the worker under test +WORKER_MOD = "nemo_rl.models.policy.workers.megatron_policy_worker" + + +# ── Mock fabric ────────────────────────────────────────────────────────── + + +def _make_mock_model(): + """A mcore-DDP-shaped mock: exposes the methods + attributes the + split-API touches, plus an ``inference_params`` attribute and a + ``modules()`` that yields nothing (so the inference-cache reset loop + is a no-op).""" + model = MagicMock() + model.config = MagicMock() + model.config.grad_sync_func = "ORIGINAL_GRAD_SYNC_FUNC" # sentinel + model.config.num_moe_experts = None # disable MoE branch + # no_sync() is a context manager — return a MagicMock that supports + # __enter__/__exit__ so the `with self.model.no_sync():` block works. + model.no_sync = MagicMock( + return_value=MagicMock( + __enter__=MagicMock(return_value=None), + __exit__=MagicMock(return_value=False), + ) + ) + model.modules = MagicMock(return_value=iter([])) + model.inference_params = None + model.parameters = MagicMock( + return_value=iter([]) + ) # no params for the rescale loop + return model + + +def _make_worker(loss_type): + """Construct a MegatronPolicyWorkerImpl instance with all heavy + attributes mocked. Bypasses __init__ via ``object.__new__``.""" + # Lazy import so the module-level mcore imports happen inside the + # mcore-marked test process. + from nemo_rl.models.policy.workers.megatron_policy_worker import ( + MegatronPolicyWorkerImpl, + ) + + w = object.__new__(MegatronPolicyWorkerImpl) + w.model = _make_mock_model() + w.optimizer = MagicMock() + # MegatronOptimizer.step returns (success, grad_norm, num_zeros) + w.optimizer.step.return_value = (True, 0.5, 0) + w.optimizer.param_groups = [{"lr": 1e-4, "weight_decay": 0.01}] + w.scheduler = MagicMock() + w.scheduler.get_lr.return_value = 1e-4 + w.scheduler.get_wd.return_value = 0.01 + w.mcore_state = MagicMock() + w.mcore_state.straggler_timer = None + w.cfg = { + "train_global_batch_size": 32, + "train_micro_batch_size": 4, + "megatron_cfg": { + "empty_unused_memory_level": 0, + "moe_per_layer_logging": False, + "use_linear_ce_fusion_loss": False, + }, + } + w.dp_size = 2 + w.cp_size = 1 + w.sampling_params = None + w.draft_model = None + w.defer_fp32_logits = False + w.dtype = torch.float32 + w._is_reward_model = False + + # Stash a loss_fn with the requested loss_type for tests that need one. + w._test_loss_fn = MagicMock(loss_type=loss_type) + return w + + +@pytest.fixture +def mock_module_symbols(): + """Patch every module-level symbol that the split-API methods call + into. Yields a dict of name → mock for assertions.""" + # Make `aggregate_training_statistics` return ({}, scalar) — what the + # finish path expects. + agg_ret = ({"loss": [0.0]}, torch.tensor(0.5)) + + patches = { + "megatron_forward_backward": [ + {"loss": 0.5, "global_valid_seqs": 8.0, "global_valid_toks": 256.0} + ], + "get_microbatch_iterator": (iter([]), 2, 4, 16, 16), # 2 pipeline mbs per call + "LossPostProcessor": MagicMock(), + "broadcast_loss_metrics_from_last_stage": lambda m: m, + "get_pg_collection": MagicMock(mp=MagicMock()), + "logical_and_across_model_parallel_group": lambda v, mp_group: v, + "reduce_max_stat_across_model_parallel_group": lambda v, mp_group: v, + "aggregate_training_statistics": agg_ret, + "get_moe_metrics": MagicMock(return_value={}), + } + + with ( + patch( + f"{WORKER_MOD}.megatron_forward_backward", + return_value=patches["megatron_forward_backward"], + ) as mfb, + patch( + f"{WORKER_MOD}.get_microbatch_iterator", + return_value=patches["get_microbatch_iterator"], + ) as gmi, + patch( + f"{WORKER_MOD}.LossPostProcessor", return_value=patches["LossPostProcessor"] + ) as lpp, + patch( + f"{WORKER_MOD}.broadcast_loss_metrics_from_last_stage", + side_effect=patches["broadcast_loss_metrics_from_last_stage"], + ) as bcast, + patch( + f"{WORKER_MOD}.get_pg_collection", return_value=patches["get_pg_collection"] + ) as gpgc, + patch( + f"{WORKER_MOD}.logical_and_across_model_parallel_group", + side_effect=patches["logical_and_across_model_parallel_group"], + ) as land, + patch( + f"{WORKER_MOD}.reduce_max_stat_across_model_parallel_group", + side_effect=patches["reduce_max_stat_across_model_parallel_group"], + ) as rmax, + patch( + f"{WORKER_MOD}.aggregate_training_statistics", + return_value=patches["aggregate_training_statistics"], + ) as agg, + patch(f"{WORKER_MOD}.get_moe_metrics", return_value={}) as moe, + patch(f"{WORKER_MOD}.get_rerun_state_machine") as grsm, + patch(f"{WORKER_MOD}.parallel_state") as pstate, + patch("torch.distributed.all_reduce") as ar, + patch("torch.cuda.empty_cache") as cec, + patch("torch.cuda.get_device_name", return_value="H100"), + patch("torch.distributed.get_rank", return_value=0), + ): + # rerun state machine: fire forward+backward once per train_microbatch + rsm = MagicMock() + rsm.should_run_forward_backward.side_effect = [True, False] * 100 + grsm.return_value = rsm + + # parallel_state mocks + pstate.is_pipeline_last_stage.return_value = True + pstate.get_data_parallel_group.return_value = MagicMock() + + yield { + "mfb": mfb, + "gmi": gmi, + "lpp": lpp, + "bcast": bcast, + "gpgc": gpgc, + "land": land, + "rmax": rmax, + "agg": agg, + "moe": moe, + "grsm": grsm, + "pstate": pstate, + "all_reduce": ar, + "empty_cache": cec, + } + + +def _fake_batch(): + """A minimal BatchedDataDict-ish object the mask-sum block can read. + train_microbatch reads ``data["sample_mask"]``, ``data["token_mask"]``, + and (only as a fallback for the no-token-mask path) ``data["input_ids"]``.""" + # 8 samples, all valid (mask=1); 256 valid tokens each + sample_mask = torch.ones(8, dtype=torch.float32) + token_mask = torch.ones(8, 257, dtype=torch.float32) # token_mask[:, 1:] → 256 toks + input_ids = torch.zeros(8, 257, dtype=torch.long) + return { + "sample_mask": sample_mask, + "token_mask": token_mask, + "input_ids": input_ids, + } + + +# ── BEGIN ──────────────────────────────────────────────────────────────── + + +class TestBegin: + def test_opens_state(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("step-0", loss_fn=w._test_loss_fn, gbs=16, mbs=4) + assert w._train_step_state is not None + assert w._train_step_state["step_id"] == "step-0" + assert w._train_step_state["loss_type"] == LossType.TOKEN_LEVEL + assert w._train_step_state["gbs"] == 16 + assert w._train_step_state["mbs"] == 4 + assert w._train_step_state["total_num_microbatches"] == 0 + + def test_calls_zero_grad_and_zero_grad_buffer(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("step-0", loss_fn=w._test_loss_fn) + w.model.zero_grad_buffer.assert_called_once() + w.optimizer.zero_grad.assert_called_once() + w.model.train.assert_called_once() + + def test_saves_and_nulls_grad_sync_func(self, mock_module_symbols): + """The PP scheduler's direct reduce dispatch must be suppressed + for the duration of the step. Otherwise PP>1 silently corrupts + grads even when ``no_sync`` is set on the bucket groups.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + assert w.model.config.grad_sync_func == "ORIGINAL_GRAD_SYNC_FUNC" + w.begin_train_step("step-0", loss_fn=w._test_loss_fn) + assert w.model.config.grad_sync_func is None + assert w._train_step_state["saved_grad_sync_func"] == "ORIGINAL_GRAD_SYNC_FUNC" + + def test_double_begin_raises(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("step-0", loss_fn=w._test_loss_fn) + with pytest.raises(RuntimeError, match="already open"): + w.begin_train_step("step-1", loss_fn=w._test_loss_fn) + + def test_uses_cfg_defaults_when_gbs_mbs_omitted(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("step-0", loss_fn=w._test_loss_fn) + assert w._train_step_state["gbs"] == w.cfg["train_global_batch_size"] + assert w._train_step_state["mbs"] == w.cfg["train_micro_batch_size"] + + +# ── _assert_step_open ──────────────────────────────────────────────────── + + +class TestAssertStepOpen: + def test_raises_when_no_step_open(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + with pytest.raises(RuntimeError, match="no train step open"): + w._assert_step_open("step-0") + + def test_raises_on_step_id_mismatch(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("step-correct", loss_fn=w._test_loss_fn) + with pytest.raises(RuntimeError, match="step_id mismatch"): + w._assert_step_open("step-WRONG") + + def test_train_microbatch_without_begin_raises(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + with pytest.raises(RuntimeError, match="no train step open"): + w.train_microbatch("step-0", _fake_batch()) + + def test_finish_without_begin_raises(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + with pytest.raises(RuntimeError, match="no train step open"): + w.finish_train_step("step-0") + + +# ── train_microbatch ───────────────────────────────────────────────────── + + +class TestTrainMicrobatch: + def test_wraps_forward_backward_in_no_sync(self, mock_module_symbols): + """The single most important assertion in this file. Without the + no_sync wrap, mcore DDP dispatches a per-call cross-DP reduce on + the partially-accumulated buffer — silently corrupting grads.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + # no_sync() must have been ENTERED (called as a context manager). + # MagicMock with __enter__/__exit__ records the __enter__ call. + ctx = w.model.no_sync.return_value + ctx.__enter__.assert_called() + ctx.__exit__.assert_called() + + def test_invokes_megatron_forward_backward_once(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + assert mock_module_symbols["mfb"].call_count == 1 + + def test_passes_placeholder_n_one_to_loss(self, mock_module_symbols): + """The N=1 trick: loss must be called with global_valid_*=1 so it + returns un-normalized sums; finish does the 1/N rescale.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + kwargs = mock_module_symbols["mfb"].call_args.kwargs + # placeholder_n is a tensor(1.0) + assert "global_valid_seqs" in kwargs + assert "global_valid_toks" in kwargs + assert float(kwargs["global_valid_seqs"].item()) == pytest.approx(1.0) + assert float(kwargs["global_valid_toks"].item()) == pytest.approx(1.0) + + def test_accumulates_mask_sums_across_calls(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + # _fake_batch has sample_mask sum = 8, token_mask*sample_mask sum = 8*256 = 2048 + w.train_microbatch("s0", _fake_batch()) + assert float(w._train_step_state["local_valid_seqs"].item()) == pytest.approx( + 8.0 + ) + assert float(w._train_step_state["local_valid_toks"].item()) == pytest.approx( + 2048.0 + ) + w.train_microbatch("s0", _fake_batch()) + assert float(w._train_step_state["local_valid_seqs"].item()) == pytest.approx( + 16.0 + ) + assert float(w._train_step_state["local_valid_toks"].item()) == pytest.approx( + 4096.0 + ) + + def test_total_num_microbatches_accumulates(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + # get_microbatch_iterator mock returns num_microbatches=2 per call + w.train_microbatch("s0", _fake_batch()) + w.train_microbatch("s0", _fake_batch()) + w.train_microbatch("s0", _fake_batch()) + assert w._train_step_state["total_num_microbatches"] == 6 + + def test_does_not_call_optimizer_step(self, mock_module_symbols): + """trainer_version semantics: optimizer.step() must NOT fire + per train_microbatch — only at finish.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + w.train_microbatch("s0", _fake_batch()) + w.optimizer.step.assert_not_called() + + +# ── finish_train_step ──────────────────────────────────────────────────── + + +class TestFinish: + def _setup_open_step(self, mock_module_symbols, loss_type): + w = _make_worker(loss_type) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + return w + + def test_rescales_grads_with_inv_n(self, mock_module_symbols): + """The 1/N rescale must happen ON the local main_grad BEFORE the + cross-DP reduce — otherwise the reduce sees un-rescaled sums.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + w.finish_train_step("s0") + # scale_gradients should have been called with some 1/N scalar < 1 + w.model.scale_gradients.assert_called_once() + arg = w.model.scale_gradients.call_args.args[0] + assert 0 < arg <= 1.0 + + def test_start_then_finish_grad_sync_called_after_rescale( + self, mock_module_symbols + ): + """Call order matters: scale_gradients -> start_grad_sync -> + finish_grad_sync -> optimizer.step.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + # Record call order via a shared list + order: list[str] = [] + w.model.scale_gradients.side_effect = lambda s: order.append("scale") + w.model.start_grad_sync.side_effect = lambda: order.append("start_sync") + w.model.finish_grad_sync.side_effect = lambda: order.append("finish_sync") + w.optimizer.step.side_effect = lambda: ( + order.append("opt_step") or (True, 0.5, 0) + ) + w.finish_train_step("s0") + assert order == ["scale", "start_sync", "finish_sync", "opt_step"] + + def test_picks_global_valid_toks_for_token_level_loss(self, mock_module_symbols): + """N selection: TOKEN_LEVEL → N = global_valid_toks (not seqs).""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + w.finish_train_step("s0") + # local_valid_toks accumulated = 2048; with mocked all_reduce as no-op, + # global_valid_toks == 2048 → inv_n = 1/2048 + arg = w.model.scale_gradients.call_args.args[0] + assert arg == pytest.approx(1.0 / 2048.0, rel=1e-4) + + def test_picks_global_valid_seqs_for_sequence_level_loss(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.SEQUENCE_LEVEL) + w.finish_train_step("s0") + # local_valid_seqs = 8 → inv_n = 1/8 + arg = w.model.scale_gradients.call_args.args[0] + assert arg == pytest.approx(1.0 / 8.0, rel=1e-4) + + def test_restores_grad_sync_func(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + w.finish_train_step("s0") + assert w.model.config.grad_sync_func == "ORIGINAL_GRAD_SYNC_FUNC" + + def test_clears_train_step_state(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + w.finish_train_step("s0") + assert w._train_step_state is None + + def test_calls_scheduler_step_with_increment_gbs(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + w._train_step_state["gbs"] = 64 + w.finish_train_step("s0") + w.scheduler.step.assert_called_once_with(increment=64) + + def test_returns_metrics_dict(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + metrics = w.finish_train_step("s0") + for key in ( + "global_loss", + "rank", + "gpu_name", + "model_dtype", + "all_mb_metrics", + "grad_norm", + ): + assert key in metrics, f"missing {key!r}" + + def test_moe_branch_skipped_when_num_experts_is_none(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = self._setup_open_step(mock_module_symbols, LossType.TOKEN_LEVEL) + w.model.config.num_moe_experts = None + metrics = w.finish_train_step("s0") + assert "moe_metrics" not in metrics + + def test_moe_branch_uses_total_num_microbatches_for_scale( + self, mock_module_symbols + ): + """MoE aux-loss scale must use the accumulated total, not the + per-call num_microbatches.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.model.config.num_moe_experts = 4 + # Have get_moe_metrics return non-empty so the branch fires + mock_module_symbols["moe"].return_value = {"aux_loss": 0.1} + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + # 3 train_microbatch calls × 2 pipeline mbs each = 6 + for _ in range(3): + w.train_microbatch("s0", _fake_batch()) + w.finish_train_step("s0") + # get_moe_metrics receives loss_scale=1/6 + kwargs = mock_module_symbols["moe"].call_args.kwargs + assert kwargs["loss_scale"] == pytest.approx(1.0 / 6.0, rel=1e-6) + + +# ── abort_train_step ───────────────────────────────────────────────────── + + +class TestAbort: + def test_restores_grad_sync_func(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.abort_train_step("s0") + assert w.model.config.grad_sync_func == "ORIGINAL_GRAD_SYNC_FUNC" + + def test_zero_grad_buffer_and_zero_grad_called(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.model.zero_grad_buffer.reset_mock() + w.optimizer.zero_grad.reset_mock() + w.abort_train_step("s0") + w.model.zero_grad_buffer.assert_called_once() + w.optimizer.zero_grad.assert_called_once() + + def test_does_not_call_optimizer_step(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + w.abort_train_step("s0") + w.optimizer.step.assert_not_called() + + def test_clears_train_step_state(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.abort_train_step("s0") + assert w._train_step_state is None + + def test_idempotent_with_no_open_step(self, mock_module_symbols): + """abort is a no-op when nothing is open.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + # Should not raise + w.abort_train_step("s0") + assert getattr(w, "_train_step_state", None) is None + + def test_mismatched_step_id_raises(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + with pytest.raises(RuntimeError, match="does not match open step"): + w.abort_train_step("s-WRONG") + + def test_can_begin_new_step_after_abort(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + w.train_microbatch("s0", _fake_batch()) + w.abort_train_step("s0") + # New step opens cleanly + w.begin_train_step("s1", loss_fn=w._test_loss_fn) + assert w._train_step_state["step_id"] == "s1" + assert float(w._train_step_state["local_valid_seqs"].item()) == 0.0 + + +# ── grad_sync_func full lifecycle (integration of begin → finish/abort) ─ + + +class TestGradSyncFuncLifecycle: + def test_begin_finish_round_trip(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + sentinel = "MY_CUSTOM_GRAD_SYNC" + w.model.config.grad_sync_func = sentinel + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + assert w.model.config.grad_sync_func is None + w.train_microbatch("s0", _fake_batch()) + w.finish_train_step("s0") + assert w.model.config.grad_sync_func == sentinel + + def test_begin_abort_round_trip(self, mock_module_symbols): + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + sentinel = "MY_CUSTOM_GRAD_SYNC" + w.model.config.grad_sync_func = sentinel + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + assert w.model.config.grad_sync_func is None + w.abort_train_step("s0") + assert w.model.config.grad_sync_func == sentinel + + def test_handles_originally_none_grad_sync_func(self, mock_module_symbols): + """When PP=1 (or align_grad_reduce=False), grad_sync_func is None + to begin with. begin → finish must leave it as None.""" + from nemo_rl.algorithms.loss.interfaces import LossType + + w = _make_worker(LossType.TOKEN_LEVEL) + w.model.config.grad_sync_func = None + w.begin_train_step("s0", loss_fn=w._test_loss_fn) + assert w.model.config.grad_sync_func is None + w.train_microbatch("s0", _fake_batch()) + w.finish_train_step("s0") + assert w.model.config.grad_sync_func is None From 22be51aebeca711544ece71bfa44015f8fb9638e Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Wed, 3 Jun 2026 22:30:32 -0700 Subject: [PATCH 02/44] squash rollout pump (e48aa9f -> 8b5d01f) Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 113 ++++--- nemo_rl/experience/rollout_manager.py | 126 +++++++- tests/unit/experience/test_rollouts.py | 16 +- tests/unit/single_controller/__init__.py | 13 + .../single_controller/test_rollout_pump.py | 290 ++++++++++++++++++ .../test_single_controller_dryrun.py | 81 +++-- 6 files changed, 548 insertions(+), 91 deletions(-) create mode 100644 tests/unit/single_controller/__init__.py create mode 100644 tests/unit/single_controller/test_rollout_pump.py rename tests/unit/{algorithms => single_controller}/test_single_controller_dryrun.py (96%) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index fb4e9051850..268f0e607d3 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -25,8 +25,8 @@ DataPlane. Model tensors still move through DataPlane or NCCL. Data flow: - _rollout_pump → gen.generate_and_push(prompt, dp_client) ← RPC to GenWorker - GenWorker → dp_client.put_samples(...) + _rollout_pump → rollout_manager.generate_and_push(prompt) + RolloutManager runs run_rollout locally then dp_client.put_samples(...) _train_pump → dp_client.claim_meta(...) → StalenessSampler → _advantage_pump(meta) → dp_client.get_samples(...) → adv_estimator.compute_advantage(...) @@ -48,13 +48,17 @@ import ray import torch from tensordict import TensorDict +from torchdata.stateful_dataloader import StatefulDataLoader from nemo_rl.algorithms.staleness_sampler import ( StalenessSampler, count_prompt_groups, min_weight_version, ) +from nemo_rl.data.interfaces import DatumSpec from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.environments.interfaces import EnvironmentInterface +from nemo_rl.experience.rollout_manager import RolloutManager log = logging.getLogger(__name__) @@ -79,7 +83,6 @@ class SingleControllerConfig: # Training max_train_steps: int = 10 - max_rollout_prompts: int = 32 # DataPlane partition partition_id: str = "rollout_data" @@ -106,6 +109,11 @@ class SingleControllerConfig: weight_nccl_addr: str = "127.0.0.1" weight_nccl_port: Optional[int] = None + # Rollout config. Read only when SC builds RolloutManager itself. + rollout_max_seq_len: int = 1024 + rollout_max_turns: Optional[int] = None + use_nemo_gym: bool = False + # Extra fields passed through to avoid TypedDict issues extra: dict = field(default_factory=dict) @@ -125,12 +133,17 @@ class SingleControllerActor: def __init__( self, cfg: SingleControllerConfig, - prompts: list[str], - dp_client_handle: Any, + dp_client: Any, gen_handle: Any, trainer_handle: Any, + env_handles: dict[str, EnvironmentInterface], + # TODO: move into SC's setup phase + dataloader: StatefulDataLoader, weight_synchronizer: Any, advantage_estimator: Any | None = None, + tokenizer: Any | None = None, + # TODO: remove later, keep here for dry run test + rollout_manager: RolloutManager | None = None, ) -> None: import logging as _logging @@ -140,10 +153,10 @@ def __init__( ) self._cfg = cfg - self._prompts = prompts - self._dp_client = dp_client_handle + self._dp_client = dp_client self._gen = gen_handle self._trainer = trainer_handle + self._dataloader = dataloader self._weight_synchronizer = weight_synchronizer self._advantage_estimator = advantage_estimator @@ -152,6 +165,21 @@ def __init__( "advantage_enabled=True requires an advantage_estimator instance" ) + if rollout_manager is None: + self._rollout_manager = RolloutManager( + tokenizer=tokenizer, + env_handles=env_handles, + num_generations_per_prompt=cfg.generations_per_prompt, + max_seq_len=cfg.rollout_max_seq_len, + max_rollout_turns=cfg.rollout_max_turns, + use_nemo_gym=cfg.use_nemo_gym, + policy_generation=gen_handle, + dp_client=dp_client, + partition_id=cfg.partition_id, + ) + else: + self._rollout_manager = rollout_manager + # Initialize sampler assert cfg.batch_selection_strategy in [ "strict_on_policy", @@ -273,47 +301,46 @@ async def _call_dp(self, method_name: str, **kwargs) -> Any: # ── the four pumps (three main pumps + advantage pump) ───────────────── async def _rollout_pump(self) -> None: - """Dispatch prompts as concurrent coroutines, one per prompt group. + """Continuously dispatch rollout tasks until cancellation. Flow per prompt: 1. Acquire _buffer_capacity slot (backpressure) - 2. Wait for _rollout_permitted (paused during weight sync) - 3. Call gen.generate_and_push(prompt, dp_client) — RPC to GenWorker - GenWorker generates and calls DataPlane put_samples directly - 4. Decrement _inflight_rollouts + 2. Acquire sem (cap concurrent in-flight rollouts) + 3. Wait for _rollout_permitted (paused during weight sync) + 4. Call rollout_manager.generate_and_push(prompt) — local async + RolloutManager runs rollout and calls DataPlane put_samples directly + 5. Decrement _inflight_rollouts """ - n = self._cfg.max_rollout_prompts sem = asyncio.Semaphore(self._cfg.max_inflight_prompts) - - start = time.monotonic() - log.info("rollout_pump: dispatching %d prompts", n) - - async def _one_group(prompt: str) -> None: - await self._buffer_capacity.acquire() - await self._rollout_permitted.wait() - async with sem: - self._inflight_rollouts += 1 - try: - await self._ray_get( - self._gen.generate_and_push.remote(prompt, self._dp_client) - ) - if self._cfg.diagnostics: - log.info(" rollout done for prompt='%s...'", prompt[:20]) - finally: - self._inflight_rollouts -= 1 - - tasks = [ - asyncio.ensure_future(_one_group(self._prompts[i % len(self._prompts)])) - for i in range(n) - ] - await asyncio.gather(*tasks) - - self._rollout_done = True - log.info( - "rollout_pump: finished %d prompts in %.2fs", - n, - time.monotonic() - start, - ) + log.info("rollout_pump: starting") + + async def _dispatch_one_prompt(prompt: DatumSpec) -> None: + self._inflight_rollouts += 1 + try: + await self._rollout_manager.generate_and_push(prompt) + if self._cfg.diagnostics: + content = "" + for i in range(len(prompt["message_log"])): + if prompt["message_log"][i]["role"] == "user": + content = prompt["message_log"][i]["content"] + break + log.info(" rollout done for prompt='%s...'", content[:20]) + finally: + self._inflight_rollouts -= 1 + sem.release() + + # TODO: add max_num_epochs and limit max_train_steps to max_num_epochs * len(dataloader) when setup + while True: + for prompt in self._dataloader: + # check if buffer is full + await self._buffer_capacity.acquire() + # check if inflight rollouts is full + await sem.acquire() + # wait for rollout to be permitted + await self._rollout_permitted.wait() + + # dispatch rollout + asyncio.create_task(_dispatch_one_prompt(prompt)) async def _train_pump(self) -> None: """Per-prompt-group streaming train loop. diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 4b6b5b9a856..04349977f82 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -15,6 +15,7 @@ import asyncio import copy import json +import uuid from typing import Any, Optional import torch @@ -22,6 +23,7 @@ from wandb import Table from nemo_rl.data.interfaces import DatumSpec +from nemo_rl.data_plane.column_io import kv_first_write from nemo_rl.distributed.batched_data_dict import BatchedDataDict from nemo_rl.environments.interfaces import EnvironmentInterface from nemo_rl.experience.interfaces import Completion, PromptGroupRecord @@ -50,7 +52,7 @@ class AsyncRolloutImpl: def __init__( self, tokenizer: TokenizerType, - task_to_env: dict[str, EnvironmentInterface], + env_handles: dict[str, EnvironmentInterface], num_generations_per_prompt: int, max_seq_len: int, policy_generation: GenerationInterface, @@ -58,7 +60,7 @@ def __init__( **kwargs: Any, ) -> None: self._tokenizer = tokenizer - self._task_to_env = task_to_env + self._env_handles = env_handles self._num_generations_per_prompt = num_generations_per_prompt self._max_seq_len = max_seq_len self._max_rollout_turns = max_rollout_turns @@ -191,7 +193,7 @@ async def _run_single_rollout( # step. In this case, need to wrap with asyncio.to_thread to make # this function yieldable. env_output = await asyncio.to_thread( - calculate_rewards, sample_batch, self._task_to_env + calculate_rewards, sample_batch, self._env_handles ) # Update reward and termination statistics @@ -387,7 +389,7 @@ class AsyncNemoGymRolloutImpl: def __init__( self, tokenizer: TokenizerType, - task_to_env: dict[str, EnvironmentInterface], + env_handles: dict[str, EnvironmentInterface], num_generations_per_prompt: int, max_seq_len: int, generation_config: GenerationConfig, @@ -395,7 +397,7 @@ def __init__( **kwargs: Any, ) -> None: self._tokenizer = tokenizer - self._task_to_env = task_to_env + self._env_handles = env_handles self._num_generations_per_prompt = num_generations_per_prompt self._max_seq_len = max_seq_len self._max_rollout_turns = max_rollout_turns @@ -478,7 +480,7 @@ async def _run_rollouts( self, inputs: list[dict], timer: Timer, timer_prefix: str ) -> tuple[list[Completion], dict[str, Any]]: """Dispatch rows to NeMo-Gym and return completions + metrics.""" - nemo_gym_env = self._task_to_env["nemo_gym"] + nemo_gym_env = self._env_handles["nemo_gym"] # Run generation. with timer.time(f"{timer_prefix}/run_rollouts"): @@ -581,18 +583,21 @@ def _compute_rollout_metrics( class RolloutManager: - """Factory that routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym).""" + """Routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym), and pushes results to TQ.""" def __init__( self, tokenizer: TokenizerType, - task_to_env: dict[str, EnvironmentInterface], + env_handles: dict[str, EnvironmentInterface], num_generations_per_prompt: int, max_seq_len: int, max_rollout_turns: Optional[int] = None, policy_generation: Optional[GenerationInterface] = None, generation_config: Optional[GenerationConfig] = None, use_nemo_gym: bool = False, + dp_client: Optional[Any] = None, + partition_id: str = "rollout_data", + task_name: str = "train", ) -> None: assert num_generations_per_prompt >= 1, ( "num_generations_per_prompt must be >= 1" @@ -613,13 +618,116 @@ def __init__( self._impl: AsyncRolloutImpl | AsyncNemoGymRolloutImpl = rollout_cls( tokenizer=tokenizer, - task_to_env=task_to_env, + env_handles=env_handles, num_generations_per_prompt=num_generations_per_prompt, max_seq_len=max_seq_len, max_rollout_turns=max_rollout_turns, # type: ignore policy_generation=policy_generation, # type: ignore generation_config=generation_config, ) + self._tokenizer = tokenizer + self._num_generations_per_prompt = num_generations_per_prompt + self._dp_client = dp_client + self._partition_id = partition_id + self._task_name = task_name + self._weight_version: int = 0 + + def set_weight_version(self, version: int) -> None: + """Set the weight_version used for rollout tags. + + Args: + version: Trainer weight version to stamp on future rollout tags. + """ + self._weight_version = int(version) async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: return await self._impl.run_rollout(input_sample) + + async def generate_and_push(self, input_sample: DatumSpec) -> None: + """Run one prompt's rollout and push the N completions to TQ in one put. + + Args: + input_sample: A single prompt (one DatumSpec entry). + """ + assert self._dp_client is not None, ( + "generate_and_push requires dp_client to be set at __init__" + ) + record = await self.run_rollout(input_sample) + bulk_batch, tags, sample_ids = self._build_tq_payload(record) + kv_first_write( + bulk_batch, + sample_ids=sample_ids, + dp_client=self._dp_client, + partition_id=self._partition_id, + task_name=self._task_name, + tags=tags, + ) + + # TODO(async-rl): tmp shim. will be removed once StalenessSampler is rewritten + # and the canonical async-RL TQ payload is locked in. + def _build_tq_payload( + self, record: PromptGroupRecord + ) -> tuple[BatchedDataDict[Any], list[dict[str, Any]], list[str]]: + """Build the bulk_batch, tags, and sample_ids that kv_first_write expects.""" + # Lazy imports: grpo and llm_message_utils both transitively pull + # experience.rollouts, so importing at module top risks a cycle. + from nemo_rl.algorithms.grpo import ( + add_grpo_token_loss_masks_and_generation_logprobs, + extract_initial_prompt_messages, + ) + from nemo_rl.data.llm_message_utils import batched_message_log_to_flat_message + + completions = record.completions + n = len(completions) + assert n > 0, "PromptGroupRecord has no completions" + + message_logs = [c.message_log for c in completions] + prompt_token_count = sum(len(m["token_ids"]) for m in record.prompt) + prompt_lengths = torch.full((n,), prompt_token_count, dtype=torch.long) + + pad_id = int(getattr(self._tokenizer, "pad_token_id", 0) or 0) + pad_kwargs = {"pad_value_dict": {"token_ids": pad_id}} + + prompt_message_logs = extract_initial_prompt_messages( + message_logs, prompt_lengths + ) + prompt_flat, _ = batched_message_log_to_flat_message( + prompt_message_logs, + **pad_kwargs, # type: ignore + ) + + add_grpo_token_loss_masks_and_generation_logprobs(message_logs) + flat, input_lengths = batched_message_log_to_flat_message( + message_logs, # type: ignore + **pad_kwargs, # type: ignore + ) + + total_reward = torch.tensor( + [float(c.reward) for c in completions], dtype=torch.float32 + ) + sample_mask = torch.ones(n, dtype=torch.float32) + + bulk_batch = BatchedDataDict[Any]( + { + "input_ids": flat["token_ids"], + "input_lengths": input_lengths, + "generation_logprobs": flat["generation_logprobs"], + "token_mask": flat["token_loss_mask"], + "sample_mask": sample_mask, + "prompt_ids_for_adv": prompt_flat["token_ids"], + "total_reward": total_reward, + } + ) + + group_uuid = str(uuid.uuid4()) + sample_ids = [f"{group_uuid}_g{i}" for i in range(n)] + tags = [ + { + "group_id": group_uuid, + "weight_version": self._weight_version, + "committed": True, + "expected_num_samples": n, + } + for _ in range(n) + ] + return bulk_batch, tags, sample_ids diff --git a/tests/unit/experience/test_rollouts.py b/tests/unit/experience/test_rollouts.py index 5bd124d935a..c604f2f1d41 100644 --- a/tests/unit/experience/test_rollouts.py +++ b/tests/unit/experience/test_rollouts.py @@ -1044,7 +1044,7 @@ def test_rollout_manager_raises_without_impl_params(): """RolloutManager raises AssertionError when required params are missing.""" common = { "tokenizer": None, - "task_to_env": {}, + "env_handles": {}, "num_generations_per_prompt": 1, "max_seq_len": 1, } @@ -1133,7 +1133,7 @@ def test_async_rollout_manager( - rollout_metrics has the expected keys with correct types - completions hold independent (not aliased) message_log objects """ - vllm_generation, rollout_tokenizer, task_to_env, _, _ = multi_step_setup_vllm_async + vllm_generation, rollout_tokenizer, env_handles, _, _ = multi_step_setup_vllm_async input_sample = single_multi_step_calculator_input_sample num_generations = 2 max_seq_len = 1024 @@ -1142,7 +1142,7 @@ def test_async_rollout_manager( manager = RolloutManager( use_nemo_gym=False, tokenizer=rollout_tokenizer, - task_to_env=task_to_env, + env_handles=env_handles, num_generations_per_prompt=num_generations, max_seq_len=max_seq_len, max_rollout_turns=max_rollout_turns, @@ -1231,7 +1231,7 @@ def test_async_rollout_manager_matches_original( TODO: remove this test together with run_async_multi_turn_rollout when the legacy path is deleted. """ - vllm_generation, rollout_tokenizer, task_to_env, _, _ = multi_step_setup_vllm_async + vllm_generation, rollout_tokenizer, env_handles, _, _ = multi_step_setup_vllm_async input_sample = single_multi_step_calculator_input_sample num_generations = 2 max_seq_len = 1024 @@ -1258,7 +1258,7 @@ def test_async_rollout_manager_matches_original( policy_generation=vllm_generation, input_batch=batch, tokenizer=rollout_tokenizer, - task_to_env=task_to_env, + task_to_env=env_handles, max_seq_len=max_seq_len, max_rollout_turns=max_rollout_turns, ) @@ -1266,7 +1266,7 @@ def test_async_rollout_manager_matches_original( manager = RolloutManager( use_nemo_gym=False, tokenizer=rollout_tokenizer, - task_to_env=task_to_env, + env_handles=env_handles, num_generations_per_prompt=num_generations, max_seq_len=max_seq_len, max_rollout_turns=max_rollout_turns, @@ -1396,7 +1396,7 @@ def test_async_nemo_gym_rollout_manager( manager = RolloutManager( use_nemo_gym=True, tokenizer=nemo_gym_tokenizer, - task_to_env={"nemo_gym": nemo_gym}, + env_handles={"nemo_gym": nemo_gym}, num_generations_per_prompt=num_generations, max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], generation_config=nemo_gym_vllm_generation.cfg, @@ -1507,7 +1507,7 @@ def test_async_nemo_gym_rollout_manager_matches_original( manager = RolloutManager( use_nemo_gym=True, tokenizer=nemo_gym_tokenizer, - task_to_env={"nemo_gym": nemo_gym}, + env_handles={"nemo_gym": nemo_gym}, num_generations_per_prompt=num_generations, max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], generation_config=nemo_gym_vllm_generation.cfg, diff --git a/tests/unit/single_controller/__init__.py b/tests/unit/single_controller/__init__.py new file mode 100644 index 00000000000..4fc25d0d3c9 --- /dev/null +++ b/tests/unit/single_controller/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py new file mode 100644 index 00000000000..2225bcf3a22 --- /dev/null +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -0,0 +1,290 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""End-to-end test: SC._rollout_pump writes the expected rows to TQ. + +Reuses test_async_rollout_manager's fixtures (real vLLM, env, tokenizer, +DatumSpec). dp_client is a NoOpDataPlaneClient wrapped in a Ray actor so the +test process can inspect TQ state after the SC actor finishes. +""" + +from __future__ import annotations + +import time +from typing import Any + +import ray +import torch +from tensordict import TensorDict + +from nemo_rl.algorithms.single_controller import ( + SingleControllerActor, + SingleControllerConfig, +) +from nemo_rl.data_plane.adapters.noop import NoOpDataPlaneClient + +# Reuse fixtures from the experience tests; same shape as test_async_rollout_manager. +from tests.unit.experience.test_rollouts import ( + initial_multi_step_calculator_batch, # noqa: F401 + multi_step_calculator_environment, # noqa: F401 + multi_step_setup_vllm_async, # noqa: F401 + rollout_cluster, # noqa: F401 + rollout_tokenizer, # noqa: F401 + single_multi_step_calculator_input_sample, # noqa: F401 +) + +_PARTITION_ID = "rollout_data" +_BULK_FIELDS = [ + "input_ids", + "input_lengths", + "generation_logprobs", + "token_mask", + "sample_mask", + "prompt_ids_for_adv", + "total_reward", +] + + +@ray.remote(num_cpus=0) +class _TQActor: + """Ray-wrapped NoOpDataPlaneClient for cross-process TQ inspection.""" + + def __init__( + self, + partition_id: str, + fields: list[str], + num_samples: int, + consumer_tasks: list[str], + ) -> None: + self._client = NoOpDataPlaneClient() + self._client.register_partition( + partition_id=partition_id, + fields=list(fields), + num_samples=int(num_samples), + consumer_tasks=list(consumer_tasks), + ) + + def put_samples( + self, + sample_ids: list[str], + partition_id: str, + fields: TensorDict | None = None, + tags: list[dict[str, Any]] | None = None, + ) -> Any: + return self._client.put_samples( + sample_ids=sample_ids, + partition_id=partition_id, + fields=fields, + tags=tags, + ) + + def claim_meta(self, **kwargs: Any) -> Any: + return self._client.claim_meta(**kwargs) + + def get_samples( + self, + sample_ids: list[str], + partition_id: str, + select_fields: list[str], + ) -> TensorDict: + return self._client.get_samples( + sample_ids=sample_ids, + partition_id=partition_id, + select_fields=list(select_fields), + ) + + def get_tags( + self, partition_id: str, sample_ids: list[str] + ) -> list[dict[str, Any]]: + rec = self._client._partitions[partition_id] + return [dict(rec.tags.get(sid, {})) for sid in sample_ids] + + def peek_count(self, partition_id: str) -> int: + return len(self._client._partitions[partition_id].rows) + + +class _SyncDPAdapter: + """Sync DataPlaneClient over a Ray actor handle. Pads nested tensors before transport.""" + + def __init__(self, handle: Any) -> None: + self._handle = handle + + def put_samples( + self, + sample_ids: list[str], + partition_id: str, + fields: TensorDict | None = None, + tags: list[dict[str, Any]] | None = None, + ) -> Any: + if fields is not None: + fields = self._padded(fields) + return ray.get( + self._handle.put_samples.remote( + sample_ids=sample_ids, + partition_id=partition_id, + fields=fields, + tags=tags, + ) + ) + + @staticmethod + def _padded(td: TensorDict) -> TensorDict: + out: dict[str, torch.Tensor] = {} + for k in td.keys(): + v = td.get(k) + if isinstance(v, torch.Tensor) and v.is_nested: + v = torch.nested.to_padded_tensor(v, padding=0) + out[k] = v + return TensorDict(out, batch_size=td.batch_size) + + +def test_rollout_pump_writes_expected_tq_data( + multi_step_setup_vllm_async, # noqa: F811 + single_multi_step_calculator_input_sample, # noqa: F811 +): + """SC._rollout_pump writes max_rollout_prompts * num_generations rows to TQ with the expected fields and tags.""" + vllm_generation, tokenizer, env_handles, _, _ = multi_step_setup_vllm_async + input_sample = single_multi_step_calculator_input_sample + + num_generations = 2 + max_rollout_prompts = 2 + expected_samples = max_rollout_prompts * num_generations + max_seq_len = 1024 + max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 + + tq_actor = _TQActor.remote( + partition_id=_PARTITION_ID, + fields=_BULK_FIELDS, + num_samples=expected_samples * 4, + consumer_tasks=["train"], + ) + dp_adapter = _SyncDPAdapter(tq_actor) + + cfg = SingleControllerConfig( + max_train_steps=1, + min_prompt_groups_per_batch=1, + generations_per_prompt=num_generations, + max_buffered_rollouts=max_rollout_prompts, + max_inflight_prompts=max_rollout_prompts, + max_weight_staleness_versions=0, + advantage_enabled=False, + diagnostics=False, + partition_id=_PARTITION_ID, + rollout_max_seq_len=max_seq_len, + rollout_max_turns=max_rollout_turns, + use_nemo_gym=False, + ) + # SingleControllerActor expects a StatefulDataLoader, but the pump only + # iterates it (`for prompt in self._dataloader`), so any iterable works. + dataloader = [input_sample] * max_rollout_prompts + + ctrl = SingleControllerActor.remote( + cfg=cfg, + dp_client=dp_adapter, + gen_handle=vllm_generation, + trainer_handle=object(), + env_handles=env_handles, + dataloader=dataloader, + weight_synchronizer=object(), + tokenizer=tokenizer, + ) + + vllm_generation.prepare_for_generation() + + # _rollout_pump runs until cancelled, so poll TQ then cancel. + pump_ref = ctrl._rollout_pump.remote() + deadline = time.monotonic() + 120.0 + while time.monotonic() < deadline: + if ray.get(tq_actor.peek_count.remote(_PARTITION_ID)) >= expected_samples: + break + time.sleep(0.5) + assert ray.get(tq_actor.peek_count.remote(_PARTITION_ID)) >= expected_samples, ( + "rollout_pump did not push expected_samples within timeout" + ) + ray.cancel(pump_ref) + try: + ray.get(pump_ref) + except (ray.exceptions.RayTaskError, ray.exceptions.TaskCancelledError): + pass + + vllm_generation.finish_generation() + + meta = ray.get( + tq_actor.claim_meta.remote( + partition_id=_PARTITION_ID, + task_name="train", + required_fields=["input_ids"], + batch_size=expected_samples * 4, + blocking=False, + timeout_s=0.0, + ) + ) + assert meta.size == expected_samples + + group_ids: set[str] = set() + for sid in meta.sample_ids: + prefix, sep, suffix = sid.rpartition("_g") + assert sep == "_g" and suffix.isdigit(), f"unexpected sample_id: {sid}" + group_ids.add(prefix) + assert len(group_ids) == max_rollout_prompts + + data = ray.get( + tq_actor.get_samples.remote( + sample_ids=meta.sample_ids, + partition_id=_PARTITION_ID, + select_fields=_BULK_FIELDS, + ) + ) + assert set(data.keys()) == set(_BULK_FIELDS), ( + f"unexpected fields: {set(data.keys())}" + ) + assert data["input_lengths"].shape[0] == expected_samples + assert torch.all(data["input_lengths"] > 0) + assert torch.allclose( + data["sample_mask"].float(), + torch.ones(expected_samples, dtype=torch.float32), + ) + + # Same deterministic prompt as test_async_rollout_manager: the model + # solves the calculator task every time -> reward == 1.0 and decoded + # tail contains " 16". + rewards = data["total_reward"].float().flatten() + assert rewards.shape == (expected_samples,) + assert torch.allclose(rewards, torch.ones(expected_samples)), ( + f"expected all rewards == 1.0, got {rewards.tolist()}" + ) + + input_ids = data["input_ids"] + input_lengths = data["input_lengths"].tolist() + token_mask = data["token_mask"] + for i in range(expected_samples): + length = int(input_lengths[i]) + decoded = tokenizer.decode( + input_ids[i, :length].tolist(), skip_special_tokens=False + ) + assert " 16" in decoded[-64:], ( + f"sample {i}: decoded tail {decoded[-64:]!r} missing ' 16'" + ) + assert int(token_mask[i, :length].sum().item()) > 0, ( + f"sample {i}: token_mask has no assistant tokens" + ) + + tags = ray.get( + tq_actor.get_tags.remote(partition_id=_PARTITION_ID, sample_ids=meta.sample_ids) + ) + for tag in tags: + assert tag["weight_version"] == 0 + assert tag["expected_num_samples"] == num_generations + assert tag["committed"] is True + assert tag["group_id"] in group_ids diff --git a/tests/unit/algorithms/test_single_controller_dryrun.py b/tests/unit/single_controller/test_single_controller_dryrun.py similarity index 96% rename from tests/unit/algorithms/test_single_controller_dryrun.py rename to tests/unit/single_controller/test_single_controller_dryrun.py index 8f32f0ef22f..f26197a93c6 100644 --- a/tests/unit/algorithms/test_single_controller_dryrun.py +++ b/tests/unit/single_controller/test_single_controller_dryrun.py @@ -411,6 +411,24 @@ def compute_advantage( return centered.unsqueeze(-1).expand(mask.shape) +class DryRunRolloutManager: + """Dry-run mock of ``RolloutManager`` for SC dry-run tests. + + Production ``RolloutManager`` is a plain (non-Ray) class living in the + SC actor's process; this mock matches that shape. Actual work (sleep + + push a fake sample to DataPlane + bump call counters) is delegated to a + ``DryRunGenWorker`` Ray actor so the test can inspect call counts, + timestamps, and weight_version from outside the SC actor. + """ + + def __init__(self, gen_actor: Any, dp_client: Any) -> None: + self._gen_actor = gen_actor + self._dp_client = dp_client + + async def generate_and_push(self, prompt: str) -> None: + await self._gen_actor.generate_and_push.remote(prompt, self._dp_client) + + class DryRunWeightSynchronizer: """Stub WeightSynchronizer — just sleeps. @@ -474,7 +492,6 @@ def _make_controller( trainer, weight_sync=None, max_train_steps=3, - max_rollout_prompts=12, min_prompt_groups_per_batch=1, generations_per_prompt=1, max_buffered_rollouts=4, @@ -486,7 +503,6 @@ def _make_controller( ): cfg = SingleControllerConfig( max_train_steps=max_train_steps, - max_rollout_prompts=max_rollout_prompts, min_prompt_groups_per_batch=min_prompt_groups_per_batch, generations_per_prompt=generations_per_prompt, max_buffered_rollouts=max_buffered_rollouts, @@ -495,17 +511,25 @@ def _make_controller( advantage_enabled=advantage_enabled, diagnostics=diagnostics, ) + + # SC expects a StatefulDataLoader, but the pump only iterates it + # (`for prompt in self._dataloader`), so a list satisfies the contract. + dataloader = [f"prompt_{i}" for i in range(10)] + if weight_sync is None: weight_sync = DryRunWeightSynchronizer(gen_handle=gen) - prompts = [f"prompt_{i}" for i in range(10)] + rollout_manager = DryRunRolloutManager(gen, dp_client) + return SingleControllerActor.remote( - cfg, - prompts, - dp_client, - gen, - trainer, - weight_sync, - advantage_estimator, + cfg=cfg, + dp_client=dp_client, + gen_handle=gen, + env_handles={}, + trainer_handle=trainer, + dataloader=dataloader, + weight_synchronizer=weight_sync, + advantage_estimator=advantage_estimator, + rollout_manager=rollout_manager, ) def test_dry_run_completes(self, ray_init): @@ -521,7 +545,6 @@ def test_dry_run_completes(self, ray_init): trainer, weight_sync, max_train_steps=3, - max_rollout_prompts=12, min_prompt_groups_per_batch=1, generations_per_prompt=1, ) @@ -545,7 +568,6 @@ def test_advantage_pump_writes_advantages_before_train(self, ray_init): gen, trainer, max_train_steps=1, - max_rollout_prompts=2, min_prompt_groups_per_batch=2, generations_per_prompt=1, advantage_enabled=True, @@ -579,7 +601,6 @@ def test_rollout_pump_runs_concurrently_with_train(self, ray_init): gen, trainer, max_train_steps=2, - max_rollout_prompts=10, min_prompt_groups_per_batch=1, generations_per_prompt=1, max_buffered_rollouts=6, @@ -617,7 +638,6 @@ def test_buffer_capacity_semaphore_blocks_rollout(self, ray_init): gen, trainer, max_train_steps=2, - max_rollout_prompts=8, min_prompt_groups_per_batch=1, generations_per_prompt=1, max_buffered_rollouts=2, # small buffer — backpressure kicks in @@ -654,7 +674,6 @@ def test_rollout_permitted_pauses_during_sync(self, ray_init): trainer, weight_sync, max_train_steps=2, - max_rollout_prompts=8, min_prompt_groups_per_batch=1, generations_per_prompt=1, ) @@ -674,7 +693,6 @@ def test_ping_returns_while_running(self, ray_init): gen, trainer, max_train_steps=5, - max_rollout_prompts=20, min_prompt_groups_per_batch=1, generations_per_prompt=1, ) @@ -932,7 +950,6 @@ def _make_controller( prompts: list[str], weight_sync=None, max_train_steps=1, - max_rollout_prompts=4, min_prompt_groups_per_batch=1, target_prompt_groups_per_step=4, generations_per_prompt=1, @@ -943,7 +960,6 @@ def _make_controller( ): cfg = SingleControllerConfig( max_train_steps=max_train_steps, - max_rollout_prompts=max_rollout_prompts, min_prompt_groups_per_batch=min_prompt_groups_per_batch, target_prompt_groups_per_step=target_prompt_groups_per_step, generations_per_prompt=generations_per_prompt, @@ -952,16 +968,25 @@ def _make_controller( max_weight_staleness_versions=max_weight_staleness_versions, batch_selection_strategy=batch_selection_strategy, ) + + # SC expects a StatefulDataLoader, but the pump only iterates it + # (`for prompt in self._dataloader`), so a list satisfies the contract. + dataloader = prompts + if weight_sync is None: weight_sync = DryRunWeightSynchronizer(gen_handle=gen) + rollout_manager = DryRunRolloutManager(gen, dp_client) + return SingleControllerActor.remote( - cfg, - prompts if prompts else ["unused"], - dp_client, - gen, - trainer, - weight_sync, - None, + cfg=cfg, + dp_client=dp_client, + gen_handle=gen, + env_handles={}, + trainer_handle=trainer, + dataloader=dataloader, + weight_synchronizer=weight_sync, + rollout_manager=rollout_manager, + advantage_estimator=None, ) def test_streaming_dispatches_in_arrival_order(self, ray_init): @@ -978,7 +1003,6 @@ def test_streaming_dispatches_in_arrival_order(self, ray_init): trainer, prompts=prompts, max_train_steps=1, - max_rollout_prompts=3, target_prompt_groups_per_step=3, min_prompt_groups_per_batch=1, ) @@ -1004,7 +1028,6 @@ def test_trainer_version_advances_only_at_finish(self, ray_init): trainer, prompts=prompts, max_train_steps=1, - max_rollout_prompts=4, target_prompt_groups_per_step=4, min_prompt_groups_per_batch=1, ) @@ -1051,7 +1074,6 @@ def test_strict_on_policy_rejects_stale_group_midstep(self, ray_init): trainer, prompts=prompts, max_train_steps=1, - max_rollout_prompts=2, target_prompt_groups_per_step=2, min_prompt_groups_per_batch=1, batch_selection_strategy="strict_on_policy", @@ -1080,7 +1102,6 @@ def test_long_tail_overlap(self, ray_init): trainer, prompts=prompts, max_train_steps=1, - max_rollout_prompts=5, target_prompt_groups_per_step=5, min_prompt_groups_per_batch=1, ) @@ -1131,7 +1152,6 @@ def test_empty_step_is_no_op(self, ray_init): trainer, prompts=["0:0.01"], max_train_steps=1, - max_rollout_prompts=0, target_prompt_groups_per_step=2, min_prompt_groups_per_batch=1, ) @@ -1152,7 +1172,6 @@ def test_clear_samples_called_once_per_step(self, ray_init): trainer, prompts=prompts, max_train_steps=1, - max_rollout_prompts=3, target_prompt_groups_per_step=3, min_prompt_groups_per_batch=1, ) From 6b05f568bf92e37f2ee786cd2c8f94a3dd042596 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 7 Jun 2026 22:48:13 -0700 Subject: [PATCH 03/44] squash staleness sampler + tq replay buffer (eadf626 -> ac5571a) Signed-off-by: Yuki Huang --- .../algorithms/async_utils/replay_buffer.py | 170 ++++--- .../async_utils/staleness_sampler.py | 114 +++++ nemo_rl/algorithms/single_controller.py | 265 ++++------ nemo_rl/algorithms/staleness_sampler.py | 201 -------- nemo_rl/experience/payload.py | 117 +++++ nemo_rl/experience/rollout_manager.py | 98 +--- pyrefly.toml | 2 +- tests/unit/algorithms/test_async_utils.py | 159 +----- .../unit/algorithms/test_staleness_sampler.py | 177 ------- .../single_controller/test_rollout_pump.py | 38 +- .../test_single_controller_dryrun.py | 453 +++++++++--------- .../test_staleness_sampler.py | 257 ++++++++++ .../test_tq_replay_buffer.py | 265 ++++++++++ 13 files changed, 1202 insertions(+), 1114 deletions(-) create mode 100644 nemo_rl/algorithms/async_utils/staleness_sampler.py delete mode 100644 nemo_rl/algorithms/staleness_sampler.py create mode 100644 nemo_rl/experience/payload.py delete mode 100644 tests/unit/algorithms/test_staleness_sampler.py create mode 100644 tests/unit/single_controller/test_staleness_sampler.py create mode 100644 tests/unit/single_controller/test_tq_replay_buffer.py diff --git a/nemo_rl/algorithms/async_utils/replay_buffer.py b/nemo_rl/algorithms/async_utils/replay_buffer.py index 22939bf72b3..62cf0b5f420 100644 --- a/nemo_rl/algorithms/async_utils/replay_buffer.py +++ b/nemo_rl/algorithms/async_utils/replay_buffer.py @@ -12,13 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio import threading as _threading +import uuid from collections import Counter +from collections.abc import Mapping from typing import Any, Iterable, Optional import ray from nemo_rl.algorithms.async_utils.interfaces import ReplayBufferProtocol +from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.experience.interfaces import PromptGroupRecord +from nemo_rl.experience.payload import pack_payload, record_to_train_batch # Classes with @ray.remote can't be inherited from, so we split the implementation out. @@ -551,93 +557,111 @@ class ReplayBuffer(ReplayBufferImpl): pass -# WIP: DO NOT USE - This class is WIP and may be changed without notice, please DO NOT USE it. -# Will be replaced by TQReplayBuffer once TQ is ready. -@ray.remote # pragma: no cover -class ReplayBufferNew(ReplayBufferImpl): - """Staleness-window replay buffer. - - -- WIP: DO NOT USE -- - This class is WIP and may be changed without notice, please DO NOT USE it. - - Differences from ReplayBuffer: - - _evict(): Stale rows (trainer_version - weight_version > max_staleness) are evicted - at the start of every sample() call. - - sample(): selects trajectories in freshest-first order (default) or FIFO order, - controlled by the sample_freshest_first flag, from whatever remains in the buffer - after eviction. - - TODO: remove when cleaning up - - max_age_steps won't be used in ReplayBufferNew; - - self.target_weight_versions won't be used in ReplayBufferNew and will be removed - when cleaning up. target_weight_versions gates generation on specific trainer steps, - which causes generation pauses; ReplayBufferNew intentionally avoids this. - - add this class to nemo_rl/algorithms/async_utils/__init__.py +class TQReplayBuffer: + """Meta cache + TQ writer for prompt-group records. + + add tensorizes one record and writes its N rows to TQ as a single group; + meta_list / weight_list keep one entry per group for sampler reads. """ def __init__( - self, max_size: int, max_staleness: int, sample_freshest_first: bool = True + self, + dp_client: Any, + partition_id: str, + *, + pad_value_dict: Mapping[str, int], ): - super().__init__(max_size) - if max_staleness < 0: - raise ValueError(f"max_staleness must be non-negative, got {max_staleness}") - self.max_staleness = max_staleness - # will move to StalenessSampler when we implement it - self.sample_freshest_first = sample_freshest_first - - def _evict(self, current_weight_version: int) -> None: - """Evict rows where trainer_version - weight_version > max_staleness. - - Must be called with self._lock held. - """ - min_valid = current_weight_version - self.max_staleness - stale = [i for i, v in enumerate(self.trajectory_versions) if v < min_valid] - self._remove_indices(stale) + self._dp_client = dp_client + self._partition_id = partition_id + self._pad_value_dict = dict(pad_value_dict) + self.meta_list: list[KVBatchMeta] = [] + self.weight_list: list[int] = [] - def sample( + async def add( self, - num_prompt_groups: int, - current_weight_version: int, - max_age_steps: int, - ) -> Optional[dict[str, Any]]: - """Sample num_prompt_groups trajectories, freshest-first. + record: PromptGroupRecord, + *, + weight_version: int, + group_id: Optional[str] = None, + ) -> KVBatchMeta: + """Tensorize record and write its N rows to TQ as one group. - Will evict stale rows before sampling, so we will get [current_weight_version - self.max_staleness, current_weight_version] valid trajectories. + Args: + record: PromptGroupRecord with N completions to tensorize. + weight_version: Trainer weight version stamped on every row's tag; must be int. + group_id: Per-group sample_id prefix; defaults to a fresh uuid4. Returns: - Dictionary with 'trajectories' and 'avg_trajectory_age' keys, or None. + KVBatchMeta for the newly written group. """ - with self._lock: - self._evict(current_weight_version) + if group_id is None: + group_id = str(uuid.uuid4()) - if not self.trajectories: - return None + train_batch = record_to_train_batch(record, pad_value_dict=self._pad_value_dict) + sample_ids, fields, tags = pack_payload( + train_batch, weight_version=weight_version, group_id=group_id + ) + meta = await self._call_dp( + "put_samples", + sample_ids=sample_ids, + partition_id=self._partition_id, + fields=fields, + tags=tags, + ) - all_indices = range(len(self.trajectory_versions)) - if self.sample_freshest_first: - all_indices = sorted( - all_indices, - key=lambda i: self.trajectory_versions[i], - reverse=True, - ) + self.meta_list.append(meta) + self.weight_list.append(weight_version) + return meta - if len(all_indices) < num_prompt_groups: - print( - f"Insufficient trajectories: have {len(all_indices)}, " - f"need {num_prompt_groups}. Waiting." - ) - return None + async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: + """Drop entries at the given indices and optionally clear them from DataPlane. - selected = all_indices[:num_prompt_groups] - sampled_weights = [self.trajectory_versions[i] for i in selected] - avg_trajectory_age = current_weight_version - sum(sampled_weights) / len( - sampled_weights + Args: + idxs: Entry indices to drop. Must be within [0, size). + remove_in_dp: If True, also clear the dropped rows from DataPlane. + + Returns: + Number of group entries removed from the buffer. + """ + if len(idxs) == 0: + return 0 + + drop_idxs = sorted(idxs, reverse=True) + if drop_idxs[0] >= len(self.meta_list): + raise IndexError( + f"TQReplayBuffer.remove: indices out of range: {drop_idxs[0]}; " + f"size={len(self.meta_list)}" ) - sampled_items = [self.trajectories[i] for i in selected] - self._remove_indices(selected) + dropped_sample_ids: list[str] = [] + for i in drop_idxs: + dropped_sample_ids.extend(self.meta_list[i].sample_ids) + del self.meta_list[i] + del self.weight_list[i] + + if remove_in_dp: + await self._call_dp( + "clear_samples", + sample_ids=dropped_sample_ids, + partition_id=self._partition_id, + ) - return { - "trajectories": sampled_items, - "avg_trajectory_age": avg_trajectory_age, - } + return len(drop_idxs) + + def size(self) -> int: + """Return the number of prompt-group entries currently held.""" + return len(self.meta_list) + + def __len__(self) -> int: + return len(self.meta_list) + + async def _call_dp(self, method_name: str, **kwargs: Any) -> Any: + """Call a DataPlaneClient method, awaiting Ray remotes if needed.""" + method = getattr(self._dp_client, method_name) + remote = getattr(method, "remote", None) + if remote is not None: + return await remote(**kwargs) + result = method(**kwargs) + if asyncio.iscoroutine(result): + return await result + return result diff --git a/nemo_rl/algorithms/async_utils/staleness_sampler.py b/nemo_rl/algorithms/async_utils/staleness_sampler.py new file mode 100644 index 00000000000..390529b4a10 --- /dev/null +++ b/nemo_rl/algorithms/async_utils/staleness_sampler.py @@ -0,0 +1,114 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Prompt-group selection over a TQReplayBuffer.""" + +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer +from nemo_rl.data_plane import KVBatchMeta + + +class StalenessSampler: + """Pick complete prompt groups inside a version staleness window. + + Defaults to FIFO (sample_freshest_first=False); pass True to prefer smallest lag. + """ + + def __init__( + self, + buffer: TQReplayBuffer, + max_staleness_versions: int, + sample_freshest_first: bool = False, + ) -> None: + if max_staleness_versions < 0: + raise ValueError( + f"max_staleness_versions must be non-negative, got " + f"{max_staleness_versions}" + ) + self._buffer = buffer + self.max_staleness_versions = max_staleness_versions + self.sample_freshest_first = sample_freshest_first + + async def select( + self, + *, + current_train_weight: int, + min_prompt_groups: int, + ) -> tuple[KVBatchMeta | None, int]: + """Return a concat of the first min_prompt_groups eligible groups, or None. + + Freshest-first (smallest lag, ties by insertion order) when + sample_freshest_first is set, else insertion-order FIFO. + Selected entries are dropped from the buffer locally; DataPlane rows survive + for the trainer and are cleared by the caller at step boundary. + + Args: + current_train_weight: Current trainer weight version. Eligibility window is + [current_train_weight - max_staleness_versions, current_train_weight]. + min_prompt_groups: Minimum groups required; returns (None, 0) below this. + + Returns: + meta: Concatenated KVBatchMeta covering num_groups groups, or None. + num_groups: Number of prompt groups in meta; 0 when meta is None. + """ + if min_prompt_groups < 1: + raise ValueError(f"min_prompt_groups must be >= 1, got {min_prompt_groups}") + + min_valid_version = max(0, current_train_weight - self.max_staleness_versions) + valid_idxs = [ + i + for i, weight in enumerate(self._buffer.weight_list) + if min_valid_version <= weight <= current_train_weight + ] + if len(valid_idxs) < min_prompt_groups: + return None, 0 + + if self.sample_freshest_first: + valid_idxs.sort( + key=lambda i: ( + current_train_weight - self._buffer.weight_list[i], + i, + ) + ) + + selected_idxs = valid_idxs[:min_prompt_groups] + selected_metas = [self._buffer.meta_list[i] for i in selected_idxs] + + await self._buffer.remove(selected_idxs, remove_in_dp=False) + + return ( + selected_metas[0].concat(*selected_metas[1:]), + len(selected_idxs), + ) + + async def evict(self, *, current_train_weight: int) -> int: + """Drop groups whose weight falls below the staleness window. + + Future entries (weight > current_train_weight) are left alone. + + Args: + current_train_weight: Current trainer weight version; groups with + weight < current_train_weight - max_staleness_versions are dropped. + + Returns: + Number of group entries removed from the buffer. + """ + min_valid_version = max(0, current_train_weight - self.max_staleness_versions) + stale_idxs = [ + i + for i, weight in enumerate(self._buffer.weight_list) + if weight < min_valid_version + ] + if not stale_idxs: + return 0 + return await self._buffer.remove(stale_idxs, remove_in_dp=True) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 268f0e607d3..60a20d9e713 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -12,29 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""SingleController: asyncio-based orchestrator for the RL training loop. +"""SingleController: asyncio orchestrator for the RL training loop. -SingleController is a CPU-only Ray actor that owns three concurrent asyncio -pumps and coordinates all other actors via lightweight RPCs. Other actors -expose methods and wait to be called. - -Key invariant: SC does not run model work. It sends control signals -(``KVBatchMeta`` and actor handles) and reads metadata. When advantage -calculation is enabled, SC fetches only the configured advantage input -columns, computes advantages, and writes that small derived column back to -DataPlane. Model tensors still move through DataPlane or NCCL. +CPU-only Ray actor that runs three concurrent pumps and coordinates the +other actors via lightweight RPCs. SC sends control signals and reads +metadata only — model tensors still move through DataPlane or NCCL. Data flow: _rollout_pump → rollout_manager.generate_and_push(prompt) - RolloutManager runs run_rollout locally then dp_client.put_samples(...) - _train_pump → dp_client.claim_meta(...) → StalenessSampler - → _advantage_pump(meta) → dp_client.get_samples(...) - → adv_estimator.compute_advantage(...) - → dp_client.put_samples(...) - → trainer.train_from_meta(meta) - Trainer → dp_client.get_samples(...) (via its own client) - → dp_client.clear_samples(...) ← SC clears after train - _sync_weights → drain _inflight_rollouts → WeightSynchronizer.sync_weights() + → TQReplayBuffer.add tensorizes the record and writes + N training rows to TQ as one prompt-group. + _train_pump → sampler.evict → buffer.remove (stale groups, with DP clear). + → sampler.select → drops chosen groups from buffer, returns + KVBatchMeta of K groups (or None); meta is already trainable. + → _advantage_pump (get → compute → put). + → trainer.train_on_meta. + → dp_client.clear_samples (trained groups; buffer already dropped). + _sync_weights → drain _inflight_rollouts → WeightSynchronizer.sync_weights. """ from __future__ import annotations @@ -50,11 +44,8 @@ from tensordict import TensorDict from torchdata.stateful_dataloader import StatefulDataLoader -from nemo_rl.algorithms.staleness_sampler import ( - StalenessSampler, - count_prompt_groups, - min_weight_version, -) +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer +from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler from nemo_rl.data.interfaces import DatumSpec from nemo_rl.data_plane import KVBatchMeta from nemo_rl.environments.interfaces import EnvironmentInterface @@ -83,12 +74,11 @@ class SingleControllerConfig: # Training max_train_steps: int = 10 + # Cap on dataloader passes; None means unbounded (cycle until cancelled). + max_num_epochs: Optional[int] = None # DataPlane partition partition_id: str = "rollout_data" - consumer_task_name: str = "train" - claim_required_fields: list[str] = field(default_factory=lambda: ["input_ids"]) - max_claim_prompt_groups: int = 8 # Advantage calculation advantage_enabled: bool = False @@ -123,8 +113,8 @@ class SingleControllerActor: """CPU-only Ray actor that orchestrates the RL training loop. Owns three concurrent asyncio tasks: - - _rollout_pump: dispatches prompts to GenerationWorkerActor - - _train_pump: claims DataPlane meta, trains, clears consumed rows + - _rollout_pump: dispatches prompts via RolloutManager → TQReplayBuffer.add + - _train_pump: evicts stale groups, samples a batch, trains, drops it - _sync_weights: drain gate + weight synchronization All other actors are passive — they expose methods and wait to be called. @@ -142,8 +132,11 @@ def __init__( weight_synchronizer: Any, advantage_estimator: Any | None = None, tokenizer: Any | None = None, - # TODO: remove later, keep here for dry run test + # TODO: remove the rollout_manager / tq_buffer overrides once SC's + # setup phase owns construction; today they let the dry-run test + # share one buffer + manager instance with SC. rollout_manager: RolloutManager | None = None, + tq_buffer: TQReplayBuffer | None = None, ) -> None: import logging as _logging @@ -165,6 +158,24 @@ def __init__( "advantage_enabled=True requires an advantage_estimator instance" ) + if cfg.target_prompt_groups_per_step is None: + cfg.target_prompt_groups_per_step = cfg.min_prompt_groups_per_batch + if cfg.target_prompt_groups_per_step < cfg.min_prompt_groups_per_batch: + raise ValueError( + f"target_prompt_groups_per_step ({cfg.target_prompt_groups_per_step}) " + f"must be >= min_prompt_groups_per_batch ({cfg.min_prompt_groups_per_batch})" + ) + + pad_id = int(getattr(tokenizer, "pad_token_id", 0) or 0) + if tq_buffer is None: + self._buffer = TQReplayBuffer( + dp_client, + partition_id=cfg.partition_id, + pad_value_dict={"token_ids": pad_id}, + ) + else: + self._buffer = tq_buffer + if rollout_manager is None: self._rollout_manager = RolloutManager( tokenizer=tokenizer, @@ -174,11 +185,15 @@ def __init__( max_rollout_turns=cfg.rollout_max_turns, use_nemo_gym=cfg.use_nemo_gym, policy_generation=gen_handle, - dp_client=dp_client, - partition_id=cfg.partition_id, + tq_buffer=self._buffer, ) else: self._rollout_manager = rollout_manager + # Ray serializes kwargs as separate cloudpickle blobs, so a + # rollout_manager and tq_buffer passed together as `.remote()` + # args deserialize as distinct buffer instances inside the actor. + # Rebind so the rollout writer and sampler share one buffer. + self._rollout_manager._tq_buffer = self._buffer # Initialize sampler assert cfg.batch_selection_strategy in [ @@ -191,14 +206,11 @@ def __init__( print( "Using strict_on_policy, auto setting max_weight_staleness_versions to 0." ) - if cfg.target_prompt_groups_per_step is None: - cfg.target_prompt_groups_per_step = cfg.min_prompt_groups_per_batch - if cfg.target_prompt_groups_per_step < cfg.min_prompt_groups_per_batch: - raise ValueError( - f"target_prompt_groups_per_step ({cfg.target_prompt_groups_per_step}) " - f"must be >= min_prompt_groups_per_batch ({cfg.min_prompt_groups_per_batch})" - ) - self._sampler = StalenessSampler(cfg.max_weight_staleness_versions) + + self._sampler = StalenessSampler( + self._buffer, + max_staleness_versions=cfg.max_weight_staleness_versions, + ) # ── asyncio state ────────────────────────────────────────────────── # Gate: cleared during _sync_weights, set when generation may proceed @@ -209,15 +221,14 @@ def __init__( self._inflight_rollouts: int = 0 # Backpressure valve: max unconsumed rollout groups allowed in DataPlane. - # Acquired before each rollout dispatch; released after clear_samples. + # Acquired before each rollout dispatch; released when the buffer + # drops a group (sampler.evict or post-train buffer.remove). self._buffer_capacity: asyncio.Semaphore = asyncio.Semaphore( cfg.max_buffered_rollouts ) self._trainer_version: int = 0 self._train_steps: int = 0 - self._rollout_done: bool = False - self._claimed_meta: KVBatchMeta | None = None self._step_consumed_sample_ids: list[str] = [] log.info( @@ -298,7 +309,7 @@ async def _call_dp(self, method_name: str, **kwargs) -> Any: return await result return result - # ── the four pumps (three main pumps + advantage pump) ───────────────── + # ── the three pumps + advantage helper ──────────────────────────────── async def _rollout_pump(self) -> None: """Continuously dispatch rollout tasks until cancellation. @@ -308,7 +319,8 @@ async def _rollout_pump(self) -> None: 2. Acquire sem (cap concurrent in-flight rollouts) 3. Wait for _rollout_permitted (paused during weight sync) 4. Call rollout_manager.generate_and_push(prompt) — local async - RolloutManager runs rollout and calls DataPlane put_samples directly + RolloutManager runs the rollout and writes the group via + TQReplayBuffer.add (→ dp_client.put_samples + meta append) 5. Decrement _inflight_rollouts """ sem = asyncio.Semaphore(self._cfg.max_inflight_prompts) @@ -329,8 +341,10 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: self._inflight_rollouts -= 1 sem.release() - # TODO: add max_num_epochs and limit max_train_steps to max_num_epochs * len(dataloader) when setup - while True: + # TODO: limit max_train_steps to max_num_epochs * len(dataloader) when setup + max_epochs = self._cfg.max_num_epochs + epoch = 0 + while max_epochs is None or epoch < max_epochs: for prompt in self._dataloader: # check if buffer is full await self._buffer_capacity.acquire() @@ -341,16 +355,22 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: # dispatch rollout asyncio.create_task(_dispatch_one_prompt(prompt)) + epoch += 1 + + log.info("rollout_pump: completed %d epoch(s)", epoch) async def _train_pump(self) -> None: - """Per-prompt-group streaming train loop. + """Drain stale groups, sample, train, drop. Per step: - - Lazy ``begin_train_step`` on first ready group. - - Per ready group: optional ``prepare_logprobs_from_meta`` → - ``_advantage_pump`` → ``train_microbatch_from_meta`` (queued). - - End-of-step: drain in-flight → ``finish_train_step`` → - single ``clear_samples`` → ``_sync_weights``. + 1. sampler.evict drops stale groups from the buffer and clears their TQ rows. + 2. sampler.select returns K prompt groups (or None) and drops them from the + buffer; DP rows survive so the trainer can read them. Already trainable — + buffer wrote training-shaped rows at rollout time. + 3. _advantage_pump(train_meta). + 4. trainer.train_on_meta(train_meta, dp_client). + 5. dp_client.clear_samples on consumed sample_ids; release _buffer_capacity + per dropped group, then sync. """ logprobs_required = ( self._cfg.advantage_policy_logprobs_field is not None @@ -366,67 +386,49 @@ async def _train_pump(self) -> None: groups_dispatched = 0 in_flight: list[ray.ObjectRef] = [] step_open = False - step_min_weight_version: int | None = None + + evicted = await self._sampler.evict( + current_train_weight=self._trainer_version, + ) + if evicted: + log.info(" evicted %d stale prompt group(s)", evicted) + for _ in range(evicted): + self._buffer_capacity.release() while groups_dispatched < target_groups: await asyncio.sleep(0) - await self._claim_available_meta() - evicted_meta = await self._evict_stale_claimed() - if evicted_meta is not None: - evicted_groups = count_prompt_groups( - evicted_meta, - generations_per_prompt=self._cfg.generations_per_prompt, - ) - for _ in range(evicted_groups): - self._buffer_capacity.release() - - group_indices = None - if self._claimed_meta is not None and self._claimed_meta.size > 0: - group_indices = self._sampler.select_one_group( - self._claimed_meta, - trainer_version=self._trainer_version, - generations_per_prompt=self._cfg.generations_per_prompt, - ) - if group_indices is None: - in_flight = await self._reap_in_flight_nonblocking(in_flight) - if ( - self._rollout_done - and len(in_flight) == 0 - and (self._claimed_meta is None or self._claimed_meta.size == 0) - ): - break - await asyncio.sleep(0.005) + # TODO @yukih: wait train pump merged, now always return min_prompt_groups_per_batch + # need to add a max_prompt_groups_per_batch + train_meta, num_groups = await self._sampler.select( + current_train_weight=self._trainer_version, + min_prompt_groups=self._cfg.min_prompt_groups_per_batch, + ) + + if train_meta is None: + await asyncio.sleep(0.05) continue - group_meta = self._claimed_meta.subset(group_indices) - self._claimed_meta = self._claimed_meta.drop(group_indices) + for _ in range(num_groups): + self._buffer_capacity.release() if logprobs_required: await self._ray_get( - self._trainer.prepare_logprobs_from_meta.remote(group_meta) + self._trainer.prepare_logprobs_from_meta.remote(train_meta) ) - group_meta = await self._advantage_pump(group_meta) + train_meta = await self._advantage_pump(train_meta) if not step_open: await self._ray_get(self._trainer.begin_train_step.remote(step_id)) step_open = True future = self._trainer.train_microbatch_from_meta.remote( - step_id, group_meta + step_id, train_meta ) in_flight.append(future) - groups_dispatched += 1 - self._buffer_capacity.release() - self._step_consumed_sample_ids.extend(group_meta.sample_ids) - group_min_v = min_weight_version(group_meta) - if group_min_v is not None: - step_min_weight_version = ( - group_min_v - if step_min_weight_version is None - else min(step_min_weight_version, group_min_v) - ) + groups_dispatched += num_groups + self._step_consumed_sample_ids.extend(train_meta.sample_ids) in_flight = await self._reap_in_flight_nonblocking(in_flight) @@ -441,19 +443,16 @@ async def _train_pump(self) -> None: self._trainer.finish_train_step.remote(step_id) ) consumed_ids = list(self._step_consumed_sample_ids) + self._step_consumed_sample_ids = [] await self._call_dp( "clear_samples", - sample_ids=consumed_ids, + sample_ids=list(consumed_ids), partition_id=self._cfg.partition_id, ) - self._step_consumed_sample_ids = [] - prev_trainer_version = self._trainer_version + self._trainer_version = result["trainer_version"] - lag = ( - prev_trainer_version - step_min_weight_version - if step_min_weight_version is not None - else 0 - ) + min_sample_version = min(t["weight_version"] for t in train_meta.tags) # type: ignore + lag = self._trainer_version - min_sample_version log.info( "train step %d/%d trainer_v=%d lag=%d batch_size=%d", self._train_steps + 1, @@ -498,6 +497,7 @@ async def _sync_weights(self) -> None: elapsed = time.monotonic() - t0 log.info(" _sync_weights: sync done in %.3fs", elapsed) + self._rollout_manager.set_weight_version(self._trainer_version) self._rollout_permitted.set() async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: @@ -571,38 +571,6 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: # ── utility helpers ──────────────────────────────────────────────────── - async def _claim_available_meta(self) -> None: - """Claim currently-ready rows and append them to the local scheduler cache. - - TODO: replace this with a non-consuming metadata listing API. - ``claim_meta`` advances TQ's per-task cursor, so SC must keep a - local cache of claimed-but-not-yet-trained samples for now. - """ - batch_size = ( - self._cfg.max_claim_prompt_groups * self._cfg.generations_per_prompt - ) - meta = await self._call_dp( - "claim_meta", - partition_id=self._cfg.partition_id, - task_name=self._cfg.consumer_task_name, - required_fields=self._claim_required_fields(), - batch_size=batch_size, - blocking=False, - timeout_s=0.0, - ) - if meta.size == 0: - return - if self._claimed_meta is None or self._claimed_meta.size == 0: - self._claimed_meta = meta - else: - self._claimed_meta = self._claimed_meta.concat(meta) - - def _claim_required_fields(self) -> list[str]: - fields = list(self._cfg.claim_required_fields) - if self._cfg.advantage_enabled: - fields.extend(self._advantage_input_fields()) - return list(dict.fromkeys(fields)) - def _advantage_input_fields(self) -> list[str]: fields = [ self._cfg.advantage_prompt_ids_field, @@ -617,33 +585,6 @@ def _advantage_input_fields(self) -> list[str]: fields.append(self._cfg.advantage_reference_logprobs_field) return list(dict.fromkeys(fields)) - async def _evict_stale_claimed(self) -> KVBatchMeta | None: - if self._claimed_meta is None or self._claimed_meta.size == 0: - return None - indices = self._sampler.evictable_indices( - self._claimed_meta, - trainer_version=self._trainer_version, - generations_per_prompt=self._cfg.generations_per_prompt, - ) - if not indices: - return None - evicted_meta = self._claimed_meta.subset(indices) - log.info( - " evicting %d stale samples from %d prompt group(s)", - evicted_meta.size, - count_prompt_groups( - evicted_meta, - generations_per_prompt=self._cfg.generations_per_prompt, - ), - ) - await self._call_dp( - "clear_samples", - sample_ids=evicted_meta.sample_ids, - partition_id=evicted_meta.partition_id, - ) - self._claimed_meta = self._claimed_meta.drop(indices) - return evicted_meta - def _tensor_field(data: TensorDict, field_name: str) -> torch.Tensor: value = data[field_name] diff --git a/nemo_rl/algorithms/staleness_sampler.py b/nemo_rl/algorithms/staleness_sampler.py deleted file mode 100644 index ed48a3d0fee..00000000000 --- a/nemo_rl/algorithms/staleness_sampler.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. -# -# 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. - -"""Prompt-group batch selection strategies for SingleController metadata.""" - -from __future__ import annotations - -from dataclasses import dataclass -from typing import Optional - -from nemo_rl.data_plane import KVBatchMeta - - -@dataclass(frozen=True) -class PromptGroup: - """Indices and scheduling metadata for one prompt group.""" - - group_id: str - indices: list[int] - weight_version: int | None - committed: bool - expected_num_samples: int - - @property - def is_complete(self) -> bool: - return len(self.indices) == self.expected_num_samples - - -class StalenessSampler: - """Select complete prompt groups inside a version staleness window.""" - - def __init__(self, max_staleness_versions: int): - self.max_staleness_versions = max_staleness_versions - - def select_indices( - self, - meta: KVBatchMeta, - *, - trainer_version: int, - min_prompt_groups: int, - generations_per_prompt: int, - ) -> Optional[list[int]]: - eligible: list[tuple[int, int, PromptGroup]] = [] - for group in _prompt_groups(meta, generations_per_prompt): - if not group.committed or not group.is_complete: - continue - if group.weight_version is None or group.weight_version > trainer_version: - continue - lag = trainer_version - group.weight_version - if lag > self.max_staleness_versions: - continue - eligible.append((lag, group.indices[0], group)) - - if len(eligible) < min_prompt_groups: - return None - - eligible.sort(key=lambda item: (item[0], item[1])) - groups = [item[2] for item in eligible[:min_prompt_groups]] - return _flatten_group_indices(groups) - - def select_one_group( - self, - meta: KVBatchMeta, - *, - trainer_version: int, - generations_per_prompt: int, - ) -> Optional[list[int]]: - eligible: list[tuple[int, int, PromptGroup]] = [] - for group in _prompt_groups(meta, generations_per_prompt): - if not group.committed or not group.is_complete: - continue - if group.weight_version is None or group.weight_version > trainer_version: - continue - lag = trainer_version - group.weight_version - if lag > self.max_staleness_versions: - continue - eligible.append((lag, group.indices[0], group)) - - if not eligible: - return None - - eligible.sort(key=lambda item: (item[0], item[1])) - return _flatten_group_indices([eligible[0][2]]) - - def evictable_indices( - self, - meta: KVBatchMeta, - *, - trainer_version: int, - generations_per_prompt: int, - ) -> list[int]: - groups = [] - for group in _prompt_groups(meta, generations_per_prompt): - if group.weight_version is None or not group.is_complete: - continue - lag = trainer_version - group.weight_version - if lag > self.max_staleness_versions: - groups.append(group) - return _flatten_group_indices(groups) - - -def count_prompt_groups( - meta: KVBatchMeta, - *, - generations_per_prompt: int, -) -> int: - """Count complete prompt groups represented by ``meta``.""" - return sum( - 1 for group in _prompt_groups(meta, generations_per_prompt) if group.is_complete - ) - - -def min_weight_version(meta: KVBatchMeta) -> int | None: - """Smallest ``weight_version`` across per-sample tags, or None if absent.""" - versions = [ - v for v in (_weight_version(tag) for tag in meta.tags or []) if v is not None - ] - return min(versions) if versions else None - - -def _prompt_groups( - meta: KVBatchMeta, - generations_per_prompt: int, -) -> list[PromptGroup]: - tags = meta.tags or [{} for _ in meta.sample_ids] - grouped: dict[str, list[int]] = {} - first_tag: dict[str, dict] = {} - - for idx, sample_id in enumerate(meta.sample_ids): - tag = tags[idx] if idx < len(tags) else {} - group_id = str(tag.get("group_id") or _group_id_from_sample_id(sample_id)) - grouped.setdefault(group_id, []).append(idx) - first_tag.setdefault(group_id, tag) - - groups: list[PromptGroup] = [] - for group_id, indices in grouped.items(): - tag = first_tag[group_id] - expected = _as_int( - tag.get( - "expected_num_samples", - tag.get( - "expected_num_keys", - tag.get("generations_per_prompt", generations_per_prompt), - ), - ) - ) - groups.append( - PromptGroup( - group_id=group_id, - indices=indices, - weight_version=_weight_version(tag), - committed=_as_bool(tag.get("committed", True)), - expected_num_samples=expected or generations_per_prompt, - ) - ) - groups.sort(key=lambda group: group.indices[0]) - return groups - - -def _flatten_group_indices(groups: list[PromptGroup]) -> list[int]: - return [idx for group in groups for idx in group.indices] - - -def _group_id_from_sample_id(sample_id: str) -> str: - prefix, sep, suffix = sample_id.rpartition("_g") - if sep and suffix.isdigit(): - return prefix - return sample_id - - -def _weight_version(tag: dict) -> int | None: - value = tag.get("weight_version", tag.get("version")) - return _as_int(value) - - -def _as_int(value) -> int | None: - if value is None: - return None - try: - return int(value) - except (TypeError, ValueError): - return None - - -def _as_bool(value) -> bool: - if isinstance(value, bool): - return value - if isinstance(value, str): - return value.lower() in {"1", "true", "yes"} - return bool(value) diff --git a/nemo_rl/experience/payload.py b/nemo_rl/experience/payload.py new file mode 100644 index 00000000000..bdf95ab290f --- /dev/null +++ b/nemo_rl/experience/payload.py @@ -0,0 +1,117 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Producer-side payload helpers for the async-RL TQ path.""" + +from collections.abc import Mapping +from typing import Any + +import numpy as np +import torch +from tensordict import TensorDict + +from nemo_rl.data_plane.codec import pack_jagged_fields +from nemo_rl.distributed.batched_data_dict import BatchedDataDict +from nemo_rl.experience.interfaces import PromptGroupRecord + + +def record_to_train_batch( + record: PromptGroupRecord, + *, + pad_value_dict: Mapping[str, int], +) -> BatchedDataDict[Any]: + """Convert one prompt group's record into a packed BatchedDataDict of N rows. + + Args: + record: Rollout's PromptGroupRecord with N completions to flatten into rows. + pad_value_dict: Field-name → pad value used by batched_message_log_to_flat_message. + + Returns: + BatchedDataDict with input_ids, input_lengths, generation_logprobs, token_mask, + sample_mask, prompt_ids_for_adv, and total_reward. + """ + # Lazy imports: grpo and llm_message_utils transitively pull + # experience.rollouts, so importing at module top risks a cycle. + from nemo_rl.algorithms.grpo import ( + add_grpo_token_loss_masks_and_generation_logprobs, + extract_initial_prompt_messages, + ) + from nemo_rl.data.llm_message_utils import batched_message_log_to_flat_message + + completions = record.completions + n = len(completions) + assert n > 0, "PromptGroupRecord has no completions" + + message_logs = [c.message_log for c in completions] + prompt_token_count = sum(len(m["token_ids"]) for m in record.prompt) + prompt_lengths = torch.full((n,), prompt_token_count, dtype=torch.long) + + prompt_message_logs = extract_initial_prompt_messages(message_logs, prompt_lengths) + prompt_flat, _ = batched_message_log_to_flat_message( + prompt_message_logs, + pad_value_dict=dict(pad_value_dict), # type: ignore + ) + + add_grpo_token_loss_masks_and_generation_logprobs(message_logs) + flat, input_lengths = batched_message_log_to_flat_message( + message_logs, # type: ignore + pad_value_dict=dict(pad_value_dict), # type: ignore + ) + + total_reward = torch.tensor( + [float(c.reward) for c in completions], dtype=torch.float32 + ) + sample_mask = torch.ones(n, dtype=torch.float32) + + return BatchedDataDict[Any]( + { + "input_ids": flat["token_ids"], + "input_lengths": input_lengths, + "generation_logprobs": flat["generation_logprobs"], + "token_mask": flat["token_loss_mask"], + "sample_mask": sample_mask, + "prompt_ids_for_adv": prompt_flat["token_ids"], + "total_reward": total_reward, + } + ) + + +def pack_payload( + train_batch: Mapping[str, Any], + *, + weight_version: int, + group_id: str, +) -> tuple[list[str], TensorDict, list[dict[str, Any]]]: + """Pack a producer batch into (sample_ids, fields, tags) for put_samples. + + Args: + train_batch: Mapping with at least input_lengths plus the tensor/object fields to send. + weight_version: Trainer weight version stamped on every row's tag. + group_id: Per-group identifier used as the sample_id prefix; the caller owns uniqueness. + + Returns: + sample_ids of the form {group_id}_g{i}, a jagged-packed TensorDict, and per-row tags. + """ + lengths = train_batch["input_lengths"] + n = int(lengths.shape[0]) + tensor_fields: dict[str, torch.Tensor | np.ndarray] = { + k: v + for k, v in train_batch.items() + if isinstance(v, torch.Tensor) + or (isinstance(v, np.ndarray) and v.dtype == object) + } + fields_td = pack_jagged_fields(tensor_fields, lengths=lengths) + sample_ids = [f"{group_id}_g{i}" for i in range(n)] + tags = [{"weight_version": weight_version} for _ in range(n)] + return sample_ids, fields_td, tags diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 04349977f82..41374a13448 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -15,15 +15,14 @@ import asyncio import copy import json -import uuid from typing import Any, Optional import torch from transformers import PreTrainedTokenizerBase from wandb import Table +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer from nemo_rl.data.interfaces import DatumSpec -from nemo_rl.data_plane.column_io import kv_first_write from nemo_rl.distributed.batched_data_dict import BatchedDataDict from nemo_rl.environments.interfaces import EnvironmentInterface from nemo_rl.experience.interfaces import Completion, PromptGroupRecord @@ -583,7 +582,7 @@ def _compute_rollout_metrics( class RolloutManager: - """Routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym), and pushes results to TQ.""" + """Routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym), and pushes results to a TQReplayBuffer.""" def __init__( self, @@ -595,9 +594,7 @@ def __init__( policy_generation: Optional[GenerationInterface] = None, generation_config: Optional[GenerationConfig] = None, use_nemo_gym: bool = False, - dp_client: Optional[Any] = None, - partition_id: str = "rollout_data", - task_name: str = "train", + tq_buffer: Optional[TQReplayBuffer] = None, ) -> None: assert num_generations_per_prompt >= 1, ( "num_generations_per_prompt must be >= 1" @@ -627,9 +624,7 @@ def __init__( ) self._tokenizer = tokenizer self._num_generations_per_prompt = num_generations_per_prompt - self._dp_client = dp_client - self._partition_id = partition_id - self._task_name = task_name + self._tq_buffer = tq_buffer self._weight_version: int = 0 def set_weight_version(self, version: int) -> None: @@ -644,90 +639,13 @@ async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: return await self._impl.run_rollout(input_sample) async def generate_and_push(self, input_sample: DatumSpec) -> None: - """Run one prompt's rollout and push the N completions to TQ in one put. + """Run one prompt's rollout and write the N completions through the buffer. Args: input_sample: A single prompt (one DatumSpec entry). """ - assert self._dp_client is not None, ( - "generate_and_push requires dp_client to be set at __init__" + assert self._tq_buffer is not None, ( + "generate_and_push requires tq_buffer to be set at __init__" ) record = await self.run_rollout(input_sample) - bulk_batch, tags, sample_ids = self._build_tq_payload(record) - kv_first_write( - bulk_batch, - sample_ids=sample_ids, - dp_client=self._dp_client, - partition_id=self._partition_id, - task_name=self._task_name, - tags=tags, - ) - - # TODO(async-rl): tmp shim. will be removed once StalenessSampler is rewritten - # and the canonical async-RL TQ payload is locked in. - def _build_tq_payload( - self, record: PromptGroupRecord - ) -> tuple[BatchedDataDict[Any], list[dict[str, Any]], list[str]]: - """Build the bulk_batch, tags, and sample_ids that kv_first_write expects.""" - # Lazy imports: grpo and llm_message_utils both transitively pull - # experience.rollouts, so importing at module top risks a cycle. - from nemo_rl.algorithms.grpo import ( - add_grpo_token_loss_masks_and_generation_logprobs, - extract_initial_prompt_messages, - ) - from nemo_rl.data.llm_message_utils import batched_message_log_to_flat_message - - completions = record.completions - n = len(completions) - assert n > 0, "PromptGroupRecord has no completions" - - message_logs = [c.message_log for c in completions] - prompt_token_count = sum(len(m["token_ids"]) for m in record.prompt) - prompt_lengths = torch.full((n,), prompt_token_count, dtype=torch.long) - - pad_id = int(getattr(self._tokenizer, "pad_token_id", 0) or 0) - pad_kwargs = {"pad_value_dict": {"token_ids": pad_id}} - - prompt_message_logs = extract_initial_prompt_messages( - message_logs, prompt_lengths - ) - prompt_flat, _ = batched_message_log_to_flat_message( - prompt_message_logs, - **pad_kwargs, # type: ignore - ) - - add_grpo_token_loss_masks_and_generation_logprobs(message_logs) - flat, input_lengths = batched_message_log_to_flat_message( - message_logs, # type: ignore - **pad_kwargs, # type: ignore - ) - - total_reward = torch.tensor( - [float(c.reward) for c in completions], dtype=torch.float32 - ) - sample_mask = torch.ones(n, dtype=torch.float32) - - bulk_batch = BatchedDataDict[Any]( - { - "input_ids": flat["token_ids"], - "input_lengths": input_lengths, - "generation_logprobs": flat["generation_logprobs"], - "token_mask": flat["token_loss_mask"], - "sample_mask": sample_mask, - "prompt_ids_for_adv": prompt_flat["token_ids"], - "total_reward": total_reward, - } - ) - - group_uuid = str(uuid.uuid4()) - sample_ids = [f"{group_uuid}_g{i}" for i in range(n)] - tags = [ - { - "group_id": group_uuid, - "weight_version": self._weight_version, - "committed": True, - "expected_num_samples": n, - } - for _ in range(n) - ] - return bulk_batch, tags, sample_ids + await self._tq_buffer.add(record, weight_version=self._weight_version) diff --git a/pyrefly.toml b/pyrefly.toml index 670c5ead087..760945fc0c9 100644 --- a/pyrefly.toml +++ b/pyrefly.toml @@ -45,6 +45,7 @@ project-includes = [ "nemo_rl/algorithms/async_utils/__init__.py", "nemo_rl/algorithms/async_utils/interfaces.py", "nemo_rl/algorithms/async_utils/replay_buffer.py", + "nemo_rl/algorithms/async_utils/staleness_sampler.py", "nemo_rl/algorithms/logits_sampling_utils.py", "nemo_rl/algorithms/loss/__init__.py", "nemo_rl/algorithms/loss/interfaces.py", @@ -52,7 +53,6 @@ project-includes = [ "nemo_rl/algorithms/opd.py", "nemo_rl/algorithms/reward_functions.py", "nemo_rl/algorithms/single_controller.py", - "nemo_rl/algorithms/staleness_sampler.py", "nemo_rl/algorithms/utils.py", "nemo_rl/algorithms/x_token/__init__.py", "nemo_rl/algorithms/x_token/utils.py", diff --git a/tests/unit/algorithms/test_async_utils.py b/tests/unit/algorithms/test_async_utils.py index b7cff7eecd7..127fc3dd25d 100644 --- a/tests/unit/algorithms/test_async_utils.py +++ b/tests/unit/algorithms/test_async_utils.py @@ -33,10 +33,7 @@ AsyncTrajectoryCollector, ReplayBuffer, ) -from nemo_rl.algorithms.async_utils.replay_buffer import ( - ReplayBufferImpl, - ReplayBufferNew, -) +from nemo_rl.algorithms.async_utils.replay_buffer import ReplayBufferImpl from nemo_rl.algorithms.grpo import ( MasterConfig, add_grpo_token_loss_masks_and_generation_logprobs, @@ -920,160 +917,6 @@ def test_replay_buffer_checkpoint_with_torch_save(self): ray.kill(buffer2) -class TestReplayBufferNew: - """Tests for ReplayBufferNew: staleness-window sampling via _evict + sample.""" - - def _make_traj(self, label: str) -> dict: - return {"batch": {"data": label}, "rollout_metrics": {}} - - def _add(self, buf, label: str, weight_version: int): - return ray.get( - buf.add.remote( - self._make_traj(label), - weight_version=weight_version, - target_weight_version=0, # unused in ReplayBufferNew - ) - ) - - def _sample(self, buf, num_groups: int, trainer_version: int): - return ray.get( - buf.sample.remote( - num_prompt_groups=num_groups, - current_weight_version=trainer_version, - max_age_steps=0, # unused in ReplayBufferNew - ) - ) - - # ------------------------------------------------------------------ - # Construction - # ------------------------------------------------------------------ - - def test_invalid_max_staleness_raises(self): - with pytest.raises(Exception): - buf = ReplayBufferNew.remote(max_size=10, max_staleness=-1) - ray.get(buf.size.remote()) - - # ------------------------------------------------------------------ - # _evict (via sample) - # ------------------------------------------------------------------ - - def test_stale_rows_evicted_before_sampling(self): - """Rows with age > max_staleness are removed before sample() selects.""" - buf = ReplayBufferNew.remote(max_size=10, max_staleness=2) - # age at trainer=4: gen_v=1 → 3 > 2 (stale), gen_v=3 → 1 ≤ 2 (valid) - self._add(buf, "stale", weight_version=1) - self._add(buf, "fresh", weight_version=3) - - result = self._sample(buf, num_groups=1, trainer_version=4) - - assert result is not None - assert result["trajectories"][0]["batch"]["data"] == "fresh" - assert ray.get(buf.size.remote()) == 0 # stale row also gone - ray.kill(buf) - - def test_all_stale_returns_none(self): - """sample() returns None when all rows are evicted as stale.""" - buf = ReplayBufferNew.remote(max_size=10, max_staleness=1) - self._add(buf, "a", weight_version=0) - self._add(buf, "b", weight_version=1) - - # trainer=5: both ages > 1 - result = self._sample(buf, num_groups=1, trainer_version=5) - - assert result is None - assert ray.get(buf.size.remote()) == 0 - ray.kill(buf) - - def test_eviction_frees_capacity(self): - """Evicting a stale row allows a subsequent add() to succeed.""" - buf = ReplayBufferNew.remote(max_size=1, max_staleness=1) - self._add(buf, "x", weight_version=1) - assert self._add(buf, "x", weight_version=1) == "full" - - # sample() at trainer=5 evicts the stale row (age 4 > 1) - self._sample(buf, num_groups=1, trainer_version=5) - - assert self._add(buf, "y", weight_version=4) == "success" - ray.kill(buf) - - def test_within_window_not_evicted(self): - """Rows whose age is within max_staleness are not evicted.""" - buf = ReplayBufferNew.remote(max_size=10, max_staleness=3) - self._add(buf, "x", weight_version=4) - - # trainer=6: age = 6 - 4 = 2 ≤ 3 → should survive - # should return None since there is only 1 row - result = self._sample(buf, num_groups=2, trainer_version=6) - assert result is None - - # this sample should still be there - assert ray.get(buf.size.remote()) == 1 - ray.kill(buf) - - # ------------------------------------------------------------------ - # sample() - # ------------------------------------------------------------------ - - @pytest.mark.parametrize("sample_freshest_first", [True, False]) - def test_sample_freshest_first(self, sample_freshest_first): - """sample() returns the freshest trajectories first.""" - buf = ReplayBufferNew.remote( - max_size=10, max_staleness=5, sample_freshest_first=sample_freshest_first - ) - for gen_v in [3, 4, 5]: - self._add(buf, f"v{gen_v}", weight_version=gen_v) - - result = self._sample(buf, num_groups=2, trainer_version=6) - - assert result is not None - data = [t["batch"]["data"] for t in result["trajectories"]] - if sample_freshest_first: - assert data == ["v5", "v4"] - else: - assert data == ["v3", "v4"] - ray.kill(buf) - - def test_sample_returns_none_when_insufficient(self): - """sample() returns None when fewer rows than requested remain after eviction.""" - buf = ReplayBufferNew.remote(max_size=10, max_staleness=5) - self._add(buf, "only", weight_version=1) - - result = self._sample(buf, num_groups=3, trainer_version=2) - - assert result is None - ray.kill(buf) - - def test_sample_returns_none_on_empty_buffer(self): - buf = ReplayBufferNew.remote(max_size=10, max_staleness=5) - result = self._sample(buf, num_groups=1, trainer_version=1) - assert result is None - ray.kill(buf) - - def test_sample_avg_trajectory_age(self): - """avg_trajectory_age is computed from the sampled generation versions.""" - buf = ReplayBufferNew.remote(max_size=10, max_staleness=5) - # freshest first: gen 8 (age 2), gen 6 (age 4) → avg = 3.0 - for gen_v in [6, 8]: - self._add(buf, f"v{gen_v}", weight_version=gen_v) - - result = self._sample(buf, num_groups=2, trainer_version=10) - - assert result is not None - assert abs(result["avg_trajectory_age"] - 3.0) < 1e-6 - ray.kill(buf) - - def test_sample_consumes_selected_rows(self): - """Rows returned by sample() are removed from the buffer.""" - buf = ReplayBufferNew.remote(max_size=10, max_staleness=5) - for gen_v in [1, 2, 3]: - self._add(buf, f"v{gen_v}", weight_version=gen_v) - - self._sample(buf, num_groups=2, trainer_version=4) - - assert ray.get(buf.size.remote()) == 1 - ray.kill(buf) - - class TestAsyncTrajectoryCollector: """Test cases for AsyncTrajectoryCollector.""" diff --git a/tests/unit/algorithms/test_staleness_sampler.py b/tests/unit/algorithms/test_staleness_sampler.py deleted file mode 100644 index 436dd122cf9..00000000000 --- a/tests/unit/algorithms/test_staleness_sampler.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. -# -# 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 StalenessSampler (focusing on select_one_group).""" - -from __future__ import annotations - -from typing import Any - -from nemo_rl.algorithms.staleness_sampler import StalenessSampler -from nemo_rl.data_plane import KVBatchMeta - - -def _meta_with_groups( - groups: list[dict[str, Any]], -) -> KVBatchMeta: - """Build a KVBatchMeta from a list of group specs. - - Each group dict has keys: group_id, weight_version, committed (default True), - expected_num_samples, num_samples (default = expected_num_samples). - """ - sample_ids: list[str] = [] - tags: list[dict[str, Any]] = [] - for g in groups: - gid = g["group_id"] - expected = g["expected_num_samples"] - n = g.get("num_samples", expected) - for i in range(n): - sample_ids.append(f"{gid}_g{i}") - tags.append( - { - "group_id": gid, - "weight_version": g["weight_version"], - "committed": g.get("committed", True), - "expected_num_samples": expected, - } - ) - return KVBatchMeta( - partition_id="rollout_data", - task_name="train", - sample_ids=sample_ids, - tags=tags, - ) - - -def test_select_one_group_returns_none_on_empty_meta(): - sampler = StalenessSampler(max_staleness_versions=2) - meta = KVBatchMeta( - partition_id="rollout_data", - task_name="train", - sample_ids=[], - tags=[], - ) - assert ( - sampler.select_one_group(meta, trainer_version=5, generations_per_prompt=1) - is None - ) - - -def test_select_one_group_returns_only_complete_group(): - sampler = StalenessSampler(max_staleness_versions=2) - meta = _meta_with_groups( - [ - {"group_id": "g0", "weight_version": 5, "expected_num_samples": 1}, - ] - ) - assert sampler.select_one_group( - meta, trainer_version=5, generations_per_prompt=1 - ) == [0] - - -def test_select_one_group_picks_lowest_lag_first(): - sampler = StalenessSampler(max_staleness_versions=3) - meta = _meta_with_groups( - [ - {"group_id": "g0", "weight_version": 3, "expected_num_samples": 1}, - {"group_id": "g1", "weight_version": 5, "expected_num_samples": 1}, - {"group_id": "g2", "weight_version": 4, "expected_num_samples": 1}, - ] - ) - # trainer=5: g0 lag=2, g1 lag=0, g2 lag=1 → picks g1 (index 1) - assert sampler.select_one_group( - meta, trainer_version=5, generations_per_prompt=1 - ) == [1] - - -def test_select_one_group_tiebreak_leftmost_wins(): - sampler = StalenessSampler(max_staleness_versions=2) - meta = _meta_with_groups( - [ - {"group_id": "g0", "weight_version": 4, "expected_num_samples": 2}, - {"group_id": "g1", "weight_version": 4, "expected_num_samples": 2}, - ] - ) - # Both lag=1. Tiebreak: leftmost indices[0]. g0 occupies [0,1], g1 [2,3] - assert sampler.select_one_group( - meta, trainer_version=5, generations_per_prompt=2 - ) == [0, 1] - - -def test_select_one_group_skips_incomplete_and_uncommitted(): - sampler = StalenessSampler(max_staleness_versions=2) - meta = _meta_with_groups( - [ - # Incomplete group: expected 2, only 1 sample - { - "group_id": "g0", - "weight_version": 5, - "expected_num_samples": 2, - "num_samples": 1, - }, - # Uncommitted group - { - "group_id": "g1", - "weight_version": 5, - "expected_num_samples": 1, - "committed": False, - }, - # Eligible group - {"group_id": "g2", "weight_version": 5, "expected_num_samples": 1}, - ] - ) - # g0 occupies idx 0; g1 idx 1; g2 idx 2 → picks g2 - assert sampler.select_one_group( - meta, trainer_version=5, generations_per_prompt=1 - ) == [2] - - -def test_select_one_group_rejects_future_version(): - sampler = StalenessSampler(max_staleness_versions=5) - meta = _meta_with_groups( - [ - {"group_id": "g0", "weight_version": 6, "expected_num_samples": 1}, - {"group_id": "g1", "weight_version": 4, "expected_num_samples": 1}, - ] - ) - # trainer=5: g0 has weight_version > trainer_version, rejected; g1 lag=1 - assert sampler.select_one_group( - meta, trainer_version=5, generations_per_prompt=1 - ) == [1] - - -def test_select_one_group_strict_on_policy(): - sampler = StalenessSampler(max_staleness_versions=0) - meta = _meta_with_groups( - [ - {"group_id": "g0", "weight_version": 4, "expected_num_samples": 1}, - {"group_id": "g1", "weight_version": 5, "expected_num_samples": 1}, - ] - ) - # strict: only weight_version==trainer_version eligible - assert sampler.select_one_group( - meta, trainer_version=5, generations_per_prompt=1 - ) == [1] - # All stale → None - meta_stale = _meta_with_groups( - [ - {"group_id": "g0", "weight_version": 4, "expected_num_samples": 1}, - ] - ) - assert ( - sampler.select_one_group( - meta_stale, trainer_version=5, generations_per_prompt=1 - ) - is None - ) diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index 2225bcf3a22..de0ab46126a 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -45,6 +45,8 @@ ) _PARTITION_ID = "rollout_data" +# TQReplayBuffer.add tensorizes each PromptGroupRecord and writes +# ``generations_per_prompt`` training rows directly to TQ. _BULK_FIELDS = [ "input_ids", "input_lengths", @@ -159,6 +161,7 @@ def test_rollout_pump_writes_expected_tq_data( num_generations = 2 max_rollout_prompts = 2 + # TQReplayBuffer.add writes ``num_generations`` training rows per prompt. expected_samples = max_rollout_prompts * num_generations max_seq_len = 1024 max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 @@ -224,7 +227,7 @@ def test_rollout_pump_writes_expected_tq_data( tq_actor.claim_meta.remote( partition_id=_PARTITION_ID, task_name="train", - required_fields=["input_ids"], + required_fields=_BULK_FIELDS, batch_size=expected_samples * 4, blocking=False, timeout_s=0.0, @@ -232,42 +235,44 @@ def test_rollout_pump_writes_expected_tq_data( ) assert meta.size == expected_samples + # pack_payload stamps sample_ids as ``{group_uuid}_g{i}``. group_ids: set[str] = set() for sid in meta.sample_ids: - prefix, sep, suffix = sid.rpartition("_g") - assert sep == "_g" and suffix.isdigit(), f"unexpected sample_id: {sid}" - group_ids.add(prefix) + head, _, tail = sid.rpartition("_g") + assert head and tail.isdigit(), f"unexpected sample_id: {sid}" + group_ids.add(head) assert len(group_ids) == max_rollout_prompts - data = ray.get( + bulk = ray.get( tq_actor.get_samples.remote( sample_ids=meta.sample_ids, partition_id=_PARTITION_ID, select_fields=_BULK_FIELDS, ) ) - assert set(data.keys()) == set(_BULK_FIELDS), ( - f"unexpected fields: {set(data.keys())}" + assert set(bulk.keys()) >= set(_BULK_FIELDS), ( + f"missing bulk fields: {set(_BULK_FIELDS) - set(bulk.keys())}" ) - assert data["input_lengths"].shape[0] == expected_samples - assert torch.all(data["input_lengths"] > 0) + + input_lengths = bulk["input_lengths"].long() + assert input_lengths.shape[0] == expected_samples + assert torch.all(input_lengths > 0) assert torch.allclose( - data["sample_mask"].float(), + bulk["sample_mask"].float(), torch.ones(expected_samples, dtype=torch.float32), ) # Same deterministic prompt as test_async_rollout_manager: the model # solves the calculator task every time -> reward == 1.0 and decoded # tail contains " 16". - rewards = data["total_reward"].float().flatten() + rewards = bulk["total_reward"].float().flatten() assert rewards.shape == (expected_samples,) assert torch.allclose(rewards, torch.ones(expected_samples)), ( f"expected all rewards == 1.0, got {rewards.tolist()}" ) - input_ids = data["input_ids"] - input_lengths = data["input_lengths"].tolist() - token_mask = data["token_mask"] + input_ids = bulk["input_ids"] + token_mask = bulk["token_mask"] for i in range(expected_samples): length = int(input_lengths[i]) decoded = tokenizer.decode( @@ -285,6 +290,5 @@ def test_rollout_pump_writes_expected_tq_data( ) for tag in tags: assert tag["weight_version"] == 0 - assert tag["expected_num_samples"] == num_generations - assert tag["committed"] is True - assert tag["group_id"] in group_ids + # Slim tag schema: weight_version is the only field producers stamp. + assert set(tag) == {"weight_version"} diff --git a/tests/unit/single_controller/test_single_controller_dryrun.py b/tests/unit/single_controller/test_single_controller_dryrun.py index f26197a93c6..6ffbde56435 100644 --- a/tests/unit/single_controller/test_single_controller_dryrun.py +++ b/tests/unit/single_controller/test_single_controller_dryrun.py @@ -47,12 +47,14 @@ os.environ["RAY_TEMP_DIR"] = _RAY_TEMP os.environ["RAY_TMPDIR"] = _RAY_TEMP +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer +from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler from nemo_rl.algorithms.single_controller import ( SingleControllerActor, SingleControllerConfig, ) -from nemo_rl.algorithms.staleness_sampler import StalenessSampler from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.experience.interfaces import Completion, PromptGroupRecord # ── Fake in-memory DataPlane ────────────────────────────────────────────── @@ -62,7 +64,7 @@ class FakeDataPlaneActor: """Minimal in-memory DataPlane actor for dry-run testing. Stores rows by sample_id and exposes the current DataPlane methods - SingleController uses: claim_meta, get_samples, and clear_samples. + SingleController uses: get_samples, and clear_samples. Not production code — used only for C-03 dry-run validation. """ @@ -108,40 +110,6 @@ def put_samples( tags=[dict(t) for t in tags] if tags is not None else None, ) - def claim_meta( - self, - partition_id: str, - task_name: str, - required_fields: list[str], - batch_size: int, - dp_rank: int | None = None, - blocking: bool = True, - timeout_s: float = 60.0, - ) -> KVBatchMeta: - del dp_rank, blocking, timeout_s - assert partition_id == self._partition_id - with self._lock: - consumed = self._consumed.setdefault(task_name, set()) - sample_ids: list[str] = [] - tags: list[dict[str, Any]] = [] - for sample_id, row in self._rows.items(): - if sample_id in consumed: - continue - if not all(field in row["fields"] for field in required_fields): - continue - sample_ids.append(sample_id) - tags.append(dict(row["tag"])) - if len(sample_ids) >= batch_size: - break - consumed.update(sample_ids) - return KVBatchMeta( - partition_id=partition_id, - task_name=task_name, - sample_ids=sample_ids, - fields=list(required_fields), - tags=tags if tags else None, - ) - def get_samples( self, sample_ids: list[str], @@ -187,54 +155,43 @@ def depth(self) -> int: class DryRunGenWorker: """Stub GenerationWorkerActor. - Implements the same interface as production GenWorker: - generate_and_push(prompt, dp_client) → pushes fake record to DataPlane - - Uses asyncio.sleep to simulate generation latency without blocking - the event loop. + Returns a PromptGroupRecord whose prompt_idx and per-completion reward + carry the call_count so the dry-run record-converter stub can reproduce + the train_batch fields deterministically. """ - def __init__(self, gen_latency_s: float = 0.1, weight_version: int = 0): + def __init__(self, gen_latency_s: float = 0.1): self._gen_latency_s = gen_latency_s - self._weight_version = weight_version self._call_count = 0 self._call_timestamps: list[float] = [] - async def generate_and_push(self, prompt: str, dp_client: Any) -> None: - """Simulate generation + push directly to DataPlane.""" + async def generate(self, prompt: str) -> PromptGroupRecord: self._call_count += 1 - call_idx = self._call_count self._call_timestamps.append(time.monotonic()) await asyncio.sleep(self._gen_latency_s) - group_id = f"group-{call_idx:04d}" - sample_id = f"{group_id}_g0" - await dp_client.put_samples.remote( - sample_ids=[sample_id], - partition_id="rollout_data", - fields=TensorDict( - { - "input_ids": torch.ones((1, 3), dtype=torch.long), - "prompt_ids_for_adv": torch.tensor( - [[self._call_count]], - dtype=torch.long, - ), - "total_reward": torch.tensor( - [float(self._call_count)], - dtype=torch.float32, - ), - "token_mask": torch.ones((1, 3), dtype=torch.float32), - "sample_mask": torch.ones(1, dtype=torch.float32), - }, - batch_size=[1], - ), - tags=[ - { - "group_id": group_id, - "weight_version": self._weight_version, - "committed": True, - "expected_num_samples": 1, - } + prompt_msg = { + "role": "user", + "token_ids": torch.tensor([self._call_count] * 3, dtype=torch.long), + } + assistant_msg = { + "role": "assistant", + "token_ids": torch.tensor([self._call_count] * 3, dtype=torch.long), + "generation_logprobs": torch.zeros(3, dtype=torch.float32), + } + return PromptGroupRecord( + prompt_idx=self._call_count, + prompt=[prompt_msg], + extra_env_info=None, + metadata={}, + completions=[ + Completion( + message_log=[prompt_msg, assistant_msg], + env_extras=None, + truncated=False, + reward=float(self._call_count), + ), ], + rollout_metrics={}, ) def get_call_count(self) -> int: @@ -243,8 +200,53 @@ def get_call_count(self) -> int: def get_call_timestamps(self) -> list[float]: return list(self._call_timestamps) - def set_weight_version(self, version: int) -> None: - self._weight_version = version + +@ray.remote(num_cpus=0) +class DryRunStaggeredGenWorker: + """Gen worker that reads latency and group label from the prompt. + + Prompt format: ``"{idx}:{latency}"``. Sleeps for ``latency`` then + returns a PromptGroupRecord tagged with ``group_id="group-{idx:04d}"``; + DryRunRolloutManager is responsible for pushing it to TQ. + """ + + def __init__(self) -> None: + self._call_timestamps: list[float] = [] + + async def generate(self, prompt: str) -> PromptGroupRecord: + idx_str, latency_str = prompt.split(":") + idx = int(idx_str) + latency = float(latency_str) + self._call_timestamps.append(time.monotonic()) + await asyncio.sleep(latency) + group_id = f"group-{idx:04d}" + prompt_msg = { + "role": "user", + "token_ids": torch.tensor([idx] * 3, dtype=torch.long), + } + assistant_msg = { + "role": "assistant", + "token_ids": torch.tensor([idx] * 3, dtype=torch.long), + "generation_logprobs": torch.zeros(3, dtype=torch.float32), + } + return PromptGroupRecord( + prompt_idx=idx, + prompt=[prompt_msg], + extra_env_info=None, + metadata={"group_id": group_id}, + completions=[ + Completion( + message_log=[prompt_msg, assistant_msg], + env_extras=None, + truncated=False, + reward=float(idx), + ), + ], + rollout_metrics={}, + ) + + def get_call_timestamps(self) -> list[float]: + return list(self._call_timestamps) @ray.remote(num_cpus=0) @@ -415,30 +417,40 @@ class DryRunRolloutManager: """Dry-run mock of ``RolloutManager`` for SC dry-run tests. Production ``RolloutManager`` is a plain (non-Ray) class living in the - SC actor's process; this mock matches that shape. Actual work (sleep + - push a fake sample to DataPlane + bump call counters) is delegated to a - ``DryRunGenWorker`` Ray actor so the test can inspect call counts, - timestamps, and weight_version from outside the SC actor. + SC actor's process and writes via ``TQReplayBuffer.add``; this mock + matches that shape. Generation is delegated to a ``DryRunGenWorker`` + Ray actor so the test can inspect call counts and timestamps from + outside the SC actor. """ - def __init__(self, gen_actor: Any, dp_client: Any) -> None: + def __init__(self, gen_actor: Any, tq_buffer: TQReplayBuffer) -> None: self._gen_actor = gen_actor - self._dp_client = dp_client + self._tq_buffer = tq_buffer + self._weight_version: int = 0 + + def set_weight_version(self, version: int) -> None: + self._weight_version = int(version) async def generate_and_push(self, prompt: str) -> None: - await self._gen_actor.generate_and_push.remote(prompt, self._dp_client) + record = await self._gen_actor.generate.remote(prompt) + group_id = (record.metadata or {}).get("group_id") + await self._tq_buffer.add( + record, + weight_version=self._weight_version, + group_id=group_id, + ) class DryRunWeightSynchronizer: - """Stub WeightSynchronizer — just sleeps. + """Stub WeightSynchronizer — bumps the rollout manager's weight_version. - In production this would call WeightSynchronizer.sync_weights() which - dispatches to IPC/HTTP/NCCL based on deployment config. + In production this would call ``WeightSynchronizer.sync_weights()`` + which dispatches to IPC/HTTP/NCCL based on deployment config and SC + then mirrors ``trainer_version`` onto the rollout manager. """ - def __init__(self, sync_latency_s: float = 0.05, gen_handle: Any = None): + def __init__(self, sync_latency_s: float = 0.05): self._sync_latency_s = sync_latency_s - self._gen_handle = gen_handle self._sync_count = 0 self._sync_timestamps: list[float] = [] @@ -446,8 +458,6 @@ async def sync_weights(self, trainer_version: int) -> None: self._sync_count += 1 self._sync_timestamps.append(time.monotonic()) await asyncio.sleep(self._sync_latency_s) - if self._gen_handle is not None: - await self._gen_handle.set_weight_version.remote(trainer_version) # ── pytest fixtures ─────────────────────────────────────────────────────── @@ -461,22 +471,39 @@ def ray_init(): # Don't shutdown — other tests in the module may need Ray -def _meta_with_versions(versions: list[int]) -> KVBatchMeta: - sample_ids = [f"g{i}_g0" for i in range(len(versions))] - return KVBatchMeta( - partition_id="rollout_data", - task_name="train", - sample_ids=sample_ids, - tags=[ - { - "group_id": f"g{i}", - "weight_version": version, - "committed": True, - "expected_num_samples": 1, - } - for i, version in enumerate(versions) - ], - ) +class _FakeBuffer: + """Mock of TQReplayBuffer exposing only the surface StalenessSampler reads.""" + + def __init__(self, partition_id: str = "rollout_data") -> None: + self._partition_id = partition_id + self.meta_list: list[KVBatchMeta] = [] + self.weight_list: list[int] = [] + + def add(self, group_id: str, weight: int, group_size: int = 1) -> None: + sample_ids = [f"{group_id}_g{i}" for i in range(group_size)] + self.meta_list.append( + KVBatchMeta( + partition_id=self._partition_id, + task_name=None, + sample_ids=sample_ids, + tags=[{"weight_version": weight, "group_id": group_id}] * group_size, + ) + ) + self.weight_list.append(weight) + + async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: + del remove_in_dp + for i in sorted(idxs, reverse=True): + del self.meta_list[i] + del self.weight_list[i] + return len(idxs) + + +def _buffer_with_versions(versions: list[int]) -> _FakeBuffer: + buf = _FakeBuffer() + for i, w in enumerate(versions): + buf.add(f"g{i}", weight=w) + return buf # ── tests ───────────────────────────────────────────────────────────────── @@ -516,9 +543,14 @@ def _make_controller( # (`for prompt in self._dataloader`), so a list satisfies the contract. dataloader = [f"prompt_{i}" for i in range(10)] + tq_buffer = TQReplayBuffer( + dp_client, + partition_id=cfg.partition_id, + pad_value_dict={"token_ids": 0}, + ) + rollout_manager = DryRunRolloutManager(gen, tq_buffer) if weight_sync is None: - weight_sync = DryRunWeightSynchronizer(gen_handle=gen) - rollout_manager = DryRunRolloutManager(gen, dp_client) + weight_sync = DryRunWeightSynchronizer() return SingleControllerActor.remote( cfg=cfg, @@ -530,6 +562,7 @@ def _make_controller( weight_synchronizer=weight_sync, advantage_estimator=advantage_estimator, rollout_manager=rollout_manager, + tq_buffer=tq_buffer, ) def test_dry_run_completes(self, ray_init): @@ -537,13 +570,11 @@ def test_dry_run_completes(self, ray_init): dp_client = FakeDataPlaneActor.remote() gen = DryRunGenWorker.remote(gen_latency_s=0.05) trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.1) - weight_sync = DryRunWeightSynchronizer(sync_latency_s=0.02, gen_handle=gen) ctrl = self._make_controller( dp_client, gen, trainer, - weight_sync, max_train_steps=3, min_prompt_groups_per_batch=1, generations_per_prompt=1, @@ -581,8 +612,8 @@ def test_advantage_pump_writes_advantages_before_train(self, ray_init): assert advantages is not None # Per-group dispatch: each group is one sample → centered advantage is 0. # The two microbatch calls are concatenated. - assert advantages.shape == (2, 3) - assert torch.allclose(advantages, torch.zeros((2, 3))) + assert advantages.shape == (2, 6) + assert torch.allclose(advantages, torch.zeros((2, 6))) def test_rollout_pump_runs_concurrently_with_train(self, ray_init): """rollout_pump dispatches while train_pump is sleeping. @@ -663,16 +694,13 @@ def test_rollout_permitted_pauses_during_sync(self, ray_init): dp_client = FakeDataPlaneActor.remote() gen = DryRunGenWorker.remote(gen_latency_s=0.05) trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.05) - weight_sync = DryRunWeightSynchronizer( - sync_latency_s=0.15, - gen_handle=gen, - ) # slow sync + weight_sync = DryRunWeightSynchronizer(sync_latency_s=0.15) # slow sync ctrl = self._make_controller( dp_client, gen, trainer, - weight_sync, + weight_sync=weight_sync, max_train_steps=2, min_prompt_groups_per_batch=1, generations_per_prompt=1, @@ -715,82 +743,72 @@ def test_ping_returns_while_running(self, ray_init): def test_staleness_sampler_filters_correctly(self): """StalenessSampler returns freshest complete groups within the window.""" - sampler = StalenessSampler(max_staleness_versions=2) - - meta = _meta_with_versions([3, 4, 5, 2, 6]) + buf = _buffer_with_versions([3, 4, 5, 2, 6]) + sampler = StalenessSampler( + buf, max_staleness_versions=2, sample_freshest_first=True + ) - indices = sampler.select_indices( - meta, - trainer_version=5, - min_prompt_groups=2, - generations_per_prompt=1, + selected, num_groups = asyncio.run( + sampler.select(current_train_weight=5, min_prompt_groups=2) ) - assert indices == [2, 1] + + assert selected is not None + # freshest-first: g2(lag 0), g1(lag 1). g3 stale, g4 future. + assert selected.sample_ids == ["g2_g0", "g1_g0"] + assert num_groups == 2 def test_staleness_sampler_returns_none_when_insufficient(self): - """StalenessSampler returns None when not enough eligible rows.""" - sampler = StalenessSampler(max_staleness_versions=1) - meta = _meta_with_versions([1]) - result = sampler.select_indices( - meta, - trainer_version=5, - min_prompt_groups=2, - generations_per_prompt=1, - ) - assert result is None + """StalenessSampler returns (None, 0) when not enough eligible rows.""" + buf = _buffer_with_versions([1]) + sampler = StalenessSampler(buf, max_staleness_versions=1) - def test_staleness_sampler_requires_complete_prompt_groups(self): - """Staleness sampler skips incomplete prompt groups.""" - sampler = StalenessSampler(max_staleness_versions=2) - meta = KVBatchMeta( - partition_id="rollout_data", - task_name="train", - sample_ids=["p0_g0", "p1_g0", "p1_g1"], - tags=[ - {"group_id": "p0", "weight_version": 5, "expected_num_samples": 2}, - {"group_id": "p1", "weight_version": 5, "expected_num_samples": 2}, - {"group_id": "p1", "weight_version": 5, "expected_num_samples": 2}, - ], + result = asyncio.run( + sampler.select(current_train_weight=5, min_prompt_groups=2) ) + assert result == (None, 0) - assert sampler.select_indices( - meta, - trainer_version=5, - min_prompt_groups=1, - generations_per_prompt=2, - ) == [1, 2] + def test_staleness_sampler_concats_multiple_groups(self): + """Selected meta concatenates whole-group sample_ids end-to-end.""" + buf = _FakeBuffer() + buf.add("g0", weight=5, group_size=2) + buf.add("g1", weight=5, group_size=2) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + selected, num_groups = asyncio.run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + assert selected is not None + assert selected.sample_ids == ["g0_g0", "g0_g1", "g1_g0", "g1_g1"] + assert num_groups == 2 def test_strict_on_policy_batch_sampler_requires_exact_version(self): """Strict sampler waits for a full batch at the trainer version.""" - sampler = StalenessSampler(max_staleness_versions=0) - meta = _meta_with_versions([4, 5, 5, 6]) - - assert ( - sampler.select_indices( - meta, - trainer_version=5, - min_prompt_groups=3, - generations_per_prompt=1, - ) - is None + buf = _buffer_with_versions([4, 5, 5, 6]) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + # Eligible at weight==5 are indices 1 and 2 only. + result = asyncio.run( + sampler.select(current_train_weight=5, min_prompt_groups=3) ) - assert sampler.select_indices( - meta, - trainer_version=5, - min_prompt_groups=2, - generations_per_prompt=1, - ) == [1, 2] + assert result == (None, 0) + + selected, num_groups = asyncio.run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + assert selected is not None + assert selected.sample_ids == ["g1_g0", "g2_g0"] + assert num_groups == 2 def test_strict_on_policy_batch_sampler_evicts_old_groups(self): - """Strict sampler marks complete old-version groups for eviction.""" - sampler = StalenessSampler(max_staleness_versions=0) - meta = _meta_with_versions([4, 5, 4]) + """Strict sampler drops complete old-version groups via buffer.remove.""" + buf = _buffer_with_versions([4, 5, 4]) + sampler = StalenessSampler(buf, max_staleness_versions=0) - assert sampler.evictable_indices( - meta, - trainer_version=5, - generations_per_prompt=1, - ) == [0, 2] + dropped = asyncio.run(sampler.evict(current_train_weight=5)) + + assert dropped == 2 + assert buf.weight_list == [5] + assert [m.sample_ids[0] for m in buf.meta_list] == ["g1_g0"] @ray.remote(num_cpus=0) @@ -893,52 +911,6 @@ def test_drytrainer_split_api_smoke(self, ray_init): ray.get(trainer.begin_train_step.remote("step-5")) -@ray.remote(num_cpus=0) -class StaggeredGenWorker: - """Gen worker that reads latency and group label from the prompt. - - Prompt format: ``"{idx}:{latency}"``. Sleeps for ``latency`` then - pushes a row with ``group_id="group-{idx}"``. - """ - - def __init__(self, weight_version: int = 0) -> None: - self._weight_version = weight_version - self._completion_timestamps: list[float] = [] - - async def generate_and_push(self, prompt: str, dp_client: Any) -> None: - idx_str, latency_str = prompt.split(":") - idx = int(idx_str) - latency = float(latency_str) - await asyncio.sleep(latency) - group_id = f"group-{idx:04d}" - sample_id = f"{group_id}_g0" - await dp_client.put_samples.remote( - sample_ids=[sample_id], - partition_id="rollout_data", - fields=TensorDict( - { - "input_ids": torch.ones((1, 3), dtype=torch.long), - }, - batch_size=[1], - ), - tags=[ - { - "group_id": group_id, - "weight_version": self._weight_version, - "committed": True, - "expected_num_samples": 1, - } - ], - ) - self._completion_timestamps.append(time.monotonic()) - - def get_completion_timestamps(self) -> list[float]: - return list(self._completion_timestamps) - - def set_weight_version(self, version: int) -> None: - self._weight_version = version - - class TestStreamingTrainPump: """Streaming train_pump end-to-end behavior under DryRunTrainer.""" @@ -957,6 +929,7 @@ def _make_controller( max_inflight_prompts=8, max_weight_staleness_versions=1, batch_selection_strategy="staleness_window", + max_num_epochs=1, ): cfg = SingleControllerConfig( max_train_steps=max_train_steps, @@ -967,6 +940,7 @@ def _make_controller( max_inflight_prompts=max_inflight_prompts, max_weight_staleness_versions=max_weight_staleness_versions, batch_selection_strategy=batch_selection_strategy, + max_num_epochs=max_num_epochs, ) # SC expects a StatefulDataLoader, but the pump only iterates it @@ -974,8 +948,14 @@ def _make_controller( dataloader = prompts if weight_sync is None: - weight_sync = DryRunWeightSynchronizer(gen_handle=gen) - rollout_manager = DryRunRolloutManager(gen, dp_client) + weight_sync = DryRunWeightSynchronizer() + + tq_buffer = TQReplayBuffer( + dp_client, + partition_id=cfg.partition_id, + pad_value_dict={"token_ids": 0}, + ) + rollout_manager = DryRunRolloutManager(gen, tq_buffer) return SingleControllerActor.remote( cfg=cfg, @@ -986,6 +966,7 @@ def _make_controller( dataloader=dataloader, weight_synchronizer=weight_sync, rollout_manager=rollout_manager, + tq_buffer=tq_buffer, advantage_estimator=None, ) @@ -993,7 +974,7 @@ def test_streaming_dispatches_in_arrival_order(self, ray_init): """SC dispatches train_microbatch in order groups commit at DP.""" dp_client = FakeDataPlaneActor.remote() # Group 0 slow, group 1 fast, group 2 medium → arrival order: 1, 2, 0 - gen = StaggeredGenWorker.remote() + gen = DryRunStaggeredGenWorker.remote() trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) prompts = ["0:0.30", "1:0.05", "2:0.15"] @@ -1018,7 +999,7 @@ def test_streaming_dispatches_in_arrival_order(self, ray_init): def test_trainer_version_advances_only_at_finish(self, ray_init): """trainer_version stays put across mb calls; ticks on finish.""" dp_client = FakeDataPlaneActor.remote() - gen = StaggeredGenWorker.remote() + gen = DryRunStaggeredGenWorker.remote() trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) prompts = [f"{i}:0.02" for i in range(4)] @@ -1064,7 +1045,7 @@ def test_strict_on_policy_rejects_stale_group_midstep(self, ray_init): ) ) del stale_meta - gen = StaggeredGenWorker.remote(weight_version=0) + gen = DryRunStaggeredGenWorker.remote() trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) prompts = [f"{i}:0.02" for i in range(2)] @@ -1090,7 +1071,7 @@ def test_long_tail_overlap(self, ray_init): """First microbatch begins before the long-tail group's rollout finishes.""" dp_client = FakeDataPlaneActor.remote() # Group 0 fast, 1-3 medium, group 4 slow - gen = StaggeredGenWorker.remote() + gen = DryRunStaggeredGenWorker.remote() trainer = DryRunTrainer.remote( dp_client, train_latency_s=0.0, microbatch_latency_s=0.0 ) @@ -1110,8 +1091,10 @@ def test_long_tail_overlap(self, ray_init): mbs = ray.get(trainer.get_microbatch_calls.remote()) assert len(mbs) == 5 first_mb_ts = mbs[0][2] - completion_ts = ray.get(gen.get_completion_timestamps.remote()) - # 5 completions; the slow group is the last one to finish + # generate() records call-time before sleep; derive completion via prompt latency. + call_ts = ray.get(gen.get_call_timestamps.remote()) + latencies = [float(p.split(":")[1]) for p in prompts] + completion_ts = [call_ts[i] + latencies[i] for i in range(len(prompts))] slow_completion = max(completion_ts) assert first_mb_ts < slow_completion, ( f"first mb dispatched at {first_mb_ts} but slow group " @@ -1144,7 +1127,7 @@ def test_abort_train_step_idempotent_and_clears_state(self, ray_init): def test_empty_step_is_no_op(self, ray_init): """No rollouts → SC exits without calling finish_train_step.""" dp_client = FakeDataPlaneActor.remote() - gen = StaggeredGenWorker.remote() + gen = DryRunStaggeredGenWorker.remote() trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) ctrl = self._make_controller( dp_client, @@ -1163,7 +1146,7 @@ def test_empty_step_is_no_op(self, ray_init): def test_clear_samples_called_once_per_step(self, ray_init): """clear_samples is called exactly once per step covering all dispatched ids.""" dp_client = FakeDataPlaneActor.remote() - gen = StaggeredGenWorker.remote() + gen = DryRunStaggeredGenWorker.remote() trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) prompts = ["0:0.01", "1:0.02", "2:0.03"] ctrl = self._make_controller( diff --git a/tests/unit/single_controller/test_staleness_sampler.py b/tests/unit/single_controller/test_staleness_sampler.py new file mode 100644 index 00000000000..866c83f2d98 --- /dev/null +++ b/tests/unit/single_controller/test_staleness_sampler.py @@ -0,0 +1,257 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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 StalenessSampler (pure filter over TQReplayBuffer state).""" + +from __future__ import annotations + +import asyncio + +import pytest + +from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler +from nemo_rl.data_plane import KVBatchMeta + + +class FakeBuffer: + """Minimal TQReplayBuffer surface used by StalenessSampler tests.""" + + def __init__(self, partition_id: str = "rollout_data") -> None: + self._partition_id = partition_id + self.meta_list: list[KVBatchMeta] = [] + self.weight_list: list[int] = [] + self.remove_calls: list[tuple[list[int], bool]] = [] + + def add(self, group_id: str, weight: int, group_size: int = 1) -> KVBatchMeta: + sample_ids = [f"{group_id}_g{i}" for i in range(group_size)] + meta = KVBatchMeta( + partition_id=self._partition_id, + task_name=None, + sample_ids=sample_ids, + tags=[{"weight_version": weight, "group_id": group_id}] * group_size, + ) + self.meta_list.append(meta) + self.weight_list.append(weight) + return meta + + async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: + self.remove_calls.append((list(idxs), remove_in_dp)) + for i in sorted(idxs, reverse=True): + del self.meta_list[i] + del self.weight_list[i] + return len(idxs) + + +def _run(coro): + return asyncio.run(coro) + + +class TestStalenessSamplerSelect: + def test_select_returns_none_when_insufficient(self): + buf = FakeBuffer() + buf.add("g0", weight=5) + sampler = StalenessSampler(buf, max_staleness_versions=2) + + result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + assert result == (None, 0) + + def test_select_returns_none_on_empty_buffer(self): + buf = FakeBuffer() + sampler = StalenessSampler(buf, max_staleness_versions=2) + + result = _run(sampler.select(current_train_weight=5, min_prompt_groups=1)) + assert result == (None, 0) + + def test_select_filters_by_staleness_window(self): + buf = FakeBuffer() + # Weights 3, 4, 5, 2, 6 against trainer=5, max_staleness=2: + # lags = 2, 1, 0, 3 (stale), -1 (future) + for i, w in enumerate([3, 4, 5, 2, 6]): + buf.add(f"g{i}", weight=w) + sampler = StalenessSampler( + buf, max_staleness_versions=2, sample_freshest_first=True + ) + + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + + assert selected is not None + # Freshest first → g2 (lag 0), g1 (lag 1) + assert selected.sample_ids == ["g2_g0", "g1_g0"] + assert num_groups == 2 + + def test_select_freshest_first_orders_by_lag(self): + buf = FakeBuffer() + for w in [3, 4, 5]: + buf.add(f"v{w}", weight=w) + sampler = StalenessSampler( + buf, max_staleness_versions=5, sample_freshest_first=True + ) + + selected, num_groups = _run( + sampler.select(current_train_weight=6, min_prompt_groups=2) + ) + assert selected is not None + assert selected.sample_ids == ["v5_g0", "v4_g0"] + assert num_groups == 2 + + def test_select_fifo_orders_by_insertion(self): + buf = FakeBuffer() + for w in [3, 4, 5]: + buf.add(f"v{w}", weight=w) + sampler = StalenessSampler( + buf, max_staleness_versions=5, sample_freshest_first=False + ) + + selected, num_groups = _run( + sampler.select(current_train_weight=6, min_prompt_groups=2) + ) + assert selected is not None + assert selected.sample_ids == ["v3_g0", "v4_g0"] + assert num_groups == 2 + + def test_select_skips_future_weight(self): + buf = FakeBuffer() + buf.add("now", weight=5) + buf.add("future", weight=7) + sampler = StalenessSampler(buf, max_staleness_versions=10) + + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=1) + ) + + assert selected is not None + assert selected.sample_ids == ["now_g0"] + assert num_groups == 1 + + def test_select_concats_groups(self): + buf = FakeBuffer() + buf.add("g0", weight=5, group_size=2) + buf.add("g1", weight=5, group_size=2) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + + assert selected is not None + assert selected.sample_ids == [ + "g0_g0", + "g0_g1", + "g1_g0", + "g1_g1", + ] + # Two groups concatenated, each of size 2 → 4 sample_ids total. + assert num_groups == 2 + + def test_select_strict_on_policy_requires_exact_version(self): + buf = FakeBuffer() + for i, w in enumerate([4, 5, 5, 6]): + buf.add(f"g{i}", weight=w) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + # 3 eligible (need weight=5), only have 2 + result = _run(sampler.select(current_train_weight=5, min_prompt_groups=3)) + assert result == (None, 0) + + # Buffer still intact: select with min=3 returned None without dropping anything. + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + assert selected is not None + assert selected.sample_ids == ["g1_g0", "g2_g0"] + assert num_groups == 2 + + def test_select_drops_returned_entries_from_buffer(self): + buf = FakeBuffer() + for i, w in enumerate([5, 5, 5]): + buf.add(f"g{i}", weight=w) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + first_meta, first_num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=1) + ) + assert first_meta is not None + assert first_meta.sample_ids == ["g0_g0"] + assert first_num_groups == 1 + assert buf.weight_list == [5, 5] + # remove_in_dp=False; DP rows kept for trainer. + assert buf.remove_calls[-1][1] is False + + second_meta, second_num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=1) + ) + assert second_meta is not None + assert second_meta.sample_ids == ["g1_g0"] + assert second_num_groups == 1 + + def test_select_rejects_zero_min_prompt_groups(self): + buf = FakeBuffer() + sampler = StalenessSampler(buf, max_staleness_versions=0) + with pytest.raises(ValueError): + _run(sampler.select(current_train_weight=0, min_prompt_groups=0)) + + +class TestStalenessSamplerEvict: + def test_evict_removes_stale_groups(self): + buf = FakeBuffer() + # trainer=5, max_staleness=1 → lag >1 means stale (weights 0, 1, 2 stale; 4, 5 fresh) + for i, w in enumerate([0, 1, 4, 5, 2]): + buf.add(f"g{i}", weight=w) + sampler = StalenessSampler(buf, max_staleness_versions=1) + + dropped = _run(sampler.evict(current_train_weight=5)) + + assert dropped == 3 + assert buf.weight_list == [4, 5] + # Survivors' sample_ids + assert [m.sample_ids[0] for m in buf.meta_list] == ["g2_g0", "g3_g0"] + + def test_evict_returns_zero_when_nothing_stale(self): + buf = FakeBuffer() + for w in [4, 5]: + buf.add(f"v{w}", weight=w) + sampler = StalenessSampler(buf, max_staleness_versions=1) + + assert _run(sampler.evict(current_train_weight=5)) == 0 + assert buf.remove_calls == [] + + def test_evict_keeps_future_groups(self): + buf = FakeBuffer() + buf.add("future", weight=7) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + assert _run(sampler.evict(current_train_weight=5)) == 0 + assert buf.weight_list == [7] + + def test_evict_drops_whole_group(self): + buf = FakeBuffer() + buf.add("stale", weight=1, group_size=4) + buf.add("fresh", weight=5, group_size=4) + sampler = StalenessSampler(buf, max_staleness_versions=1) + + dropped = _run(sampler.evict(current_train_weight=5)) + + assert dropped == 1 + assert buf.remove_calls == [([0], True)] + assert buf.weight_list == [5] + assert [m.sample_ids[0] for m in buf.meta_list] == ["fresh_g0"] + + +class TestStalenessSamplerInit: + def test_rejects_negative_max_staleness(self): + buf = FakeBuffer() + with pytest.raises(ValueError): + StalenessSampler(buf, max_staleness_versions=-1) diff --git a/tests/unit/single_controller/test_tq_replay_buffer.py b/tests/unit/single_controller/test_tq_replay_buffer.py new file mode 100644 index 00000000000..162c07ac14f --- /dev/null +++ b/tests/unit/single_controller/test_tq_replay_buffer.py @@ -0,0 +1,265 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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 TQReplayBuffer (plain SC-process buffer + TQ proxy).""" + +from __future__ import annotations + +import asyncio +from typing import Any + +import pytest +import torch + +import nemo_rl.algorithms.async_utils.replay_buffer as _replay_buffer_module +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer +from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.distributed.batched_data_dict import BatchedDataDict +from nemo_rl.experience.interfaces import PromptGroupRecord + +# Each record yields _N_GENS training rows. +_N_GENS = 2 + + +def _stub_record_to_train_batch( + record: PromptGroupRecord, *, pad_value_dict: Any +) -> BatchedDataDict[Any]: + del record, pad_value_dict + return BatchedDataDict[Any]( + { + "input_ids": torch.ones((_N_GENS, 3), dtype=torch.long), + "input_lengths": torch.full((_N_GENS,), 3, dtype=torch.long), + "total_reward": torch.zeros(_N_GENS, dtype=torch.float32), + } + ) + + +@pytest.fixture(autouse=True) +def _patch_converter(monkeypatch): + """Bypass the real ``record_to_train_batch`` so tests can use empty records.""" + monkeypatch.setattr( + _replay_buffer_module, + "record_to_train_batch", + _stub_record_to_train_batch, + ) + + +class FakeDataPlaneClient: + """Sync in-memory DataPlaneClient stub used by TQReplayBuffer tests.""" + + def __init__(self, partition_id: str = "rollout_data") -> None: + self._partition_id = partition_id + self._rows: dict[str, dict[str, Any]] = {} + self.put_calls: list[dict[str, Any]] = [] + self.clear_calls: list[list[str]] = [] + + def put_samples( + self, + sample_ids: list[str], + partition_id: str, + fields: Any = None, + tags: list[dict[str, Any]] | None = None, + ) -> KVBatchMeta: + assert partition_id == self._partition_id + self.put_calls.append( + { + "sample_ids": list(sample_ids), + "fields": fields, + "tags": [dict(t) for t in tags] if tags is not None else None, + } + ) + for i, sid in enumerate(sample_ids): + self._rows[sid] = { + "tag": dict(tags[i]) if tags is not None else {}, + } + return KVBatchMeta( + partition_id=partition_id, + task_name=None, + sample_ids=list(sample_ids), + fields=None, + tags=[dict(t) for t in tags] if tags is not None else None, + ) + + def clear_samples(self, sample_ids: list[str] | None, partition_id: str) -> None: + assert partition_id == self._partition_id + ids = list(sample_ids) if sample_ids is not None else list(self._rows) + self.clear_calls.append(list(ids)) + for sid in ids: + self._rows.pop(sid, None) + + def depth(self) -> int: + return len(self._rows) + + +def _run(coro): + return asyncio.run(coro) + + +def _make_record() -> PromptGroupRecord: + """Opaque PromptGroupRecord — converter is stubbed, so contents are unused.""" + return PromptGroupRecord( + prompt_idx=0, + prompt=[], + extra_env_info=None, + metadata={}, + completions=[], + rollout_metrics={}, + ) + + +def _make_buffer(dp: FakeDataPlaneClient) -> TQReplayBuffer: + return TQReplayBuffer( + dp, partition_id="rollout_data", pad_value_dict={"token_ids": 0} + ) + + +def _add_group(buf: TQReplayBuffer, weight: int) -> KVBatchMeta: + return _run(buf.add(_make_record(), weight_version=weight)) + + +class TestTQReplayBufferAdd: + def test_add_writes_tq_then_appends_meta(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + + meta = _run(buf.add(_make_record(), weight_version=3)) + + # pack_payload stamps sample_ids as ``{group_uuid}_g{i}``. + assert len(meta.sample_ids) == _N_GENS + group_uuid, _, idx = meta.sample_ids[0].rpartition("_g") + assert group_uuid and idx == "0" + assert all(sid.startswith(group_uuid + "_g") for sid in meta.sample_ids) + assert dp.depth() == _N_GENS + assert buf.size() == 1 + assert buf.weight_list == [3] + assert buf.meta_list[0].sample_ids == meta.sample_ids + assert meta.tags == [{"weight_version": 3}] * _N_GENS + assert len(dp.put_calls) == 1 + + def test_add_rejects_non_int_weight_version(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + with pytest.raises(TypeError): + _run( + buf.add( + _make_record(), + weight_version=None, # type: ignore[arg-type] + ) + ) + assert dp.depth() == 0 + assert buf.size() == 0 + + def test_add_rejects_bool_weight_version(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + with pytest.raises(TypeError): + _run( + buf.add( + _make_record(), + weight_version=True, # type: ignore[arg-type] + ) + ) + + def test_add_appends_multiple_records_in_order(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + + metas = [_add_group(buf, weight=w) for w in (1, 2, 3)] + + assert buf.size() == 3 + assert buf.weight_list == [1, 2, 3] + assert [m.sample_ids for m in buf.meta_list] == [ + list(metas[0].sample_ids), + list(metas[1].sample_ids), + list(metas[2].sample_ids), + ] + + +class TestTQReplayBufferRemove: + def test_remove_drops_indices_and_clears_dp_when_requested(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + metas = [_add_group(buf, weight=g) for g in range(3)] + + n = _run(buf.remove([0, 2], remove_in_dp=True)) + + assert n == 2 + assert buf.size() == 1 + assert buf.weight_list == [1] + assert buf.meta_list[0].sample_ids == list(metas[1].sample_ids) + assert dp.depth() == _N_GENS + assert set(dp._rows) == set(metas[1].sample_ids) + + def test_remove_without_dp_keeps_rows(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + metas = [_add_group(buf, weight=g) for g in range(2)] + + n = _run(buf.remove([0], remove_in_dp=False)) + + assert n == 1 + assert buf.size() == 1 + assert buf.weight_list == [1] + assert buf.meta_list[0].sample_ids == list(metas[1].sample_ids) + assert dp.clear_calls == [] + assert dp.depth() == 2 * _N_GENS + + def test_remove_rejects_out_of_range_before_mutating(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + metas = [_add_group(buf, weight=g) for g in range(2)] + + with pytest.raises(IndexError, match=r"out of range: 5; size=2"): + _run(buf.remove([0, 5], remove_in_dp=True)) + + assert buf.size() == 2 + assert [m.sample_ids for m in buf.meta_list] == [ + list(metas[0].sample_ids), + list(metas[1].sample_ids), + ] + assert dp.depth() == 2 * _N_GENS + assert dp.clear_calls == [] + + def test_remove_empty_is_noop(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + _add_group(buf, weight=0) + _add_group(buf, weight=0) + + n = _run(buf.remove([], remove_in_dp=True)) + + assert n == 0 + assert buf.size() == 2 + assert dp.depth() == 2 * _N_GENS + assert dp.clear_calls == [] + + +class TestTQReplayBufferSize: + def test_size_and_len(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + assert buf.size() == 0 + assert len(buf) == 0 + + _add_group(buf, weight=0) + assert buf.size() == 1 + assert len(buf) == 1 + + _add_group(buf, weight=0) + assert buf.size() == 2 + assert len(buf) == 2 + + _run(buf.remove([0], remove_in_dp=True)) + assert buf.size() == 1 + assert len(buf) == 1 From e96130320a08e465c033ce87b8323e9aeadc7558 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 14 Jun 2026 09:06:52 -0700 Subject: [PATCH 04/44] [rollout pump] fix batch Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 60a20d9e713..49e9521ddb9 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -345,16 +345,21 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: max_epochs = self._cfg.max_num_epochs epoch = 0 while max_epochs is None or epoch < max_epochs: - for prompt in self._dataloader: - # check if buffer is full - await self._buffer_capacity.acquire() - # check if inflight rollouts is full - await sem.acquire() - # wait for rollout to be permitted - await self._rollout_permitted.wait() - - # dispatch rollout - asyncio.create_task(_dispatch_one_prompt(prompt)) + for prompt_batch in self._dataloader: + for prompt_idx in range(prompt_batch.size): + prompt: DatumSpec = { + k: v[prompt_idx] for k, v in prompt_batch.items() + } + + # check if buffer is full + await self._buffer_capacity.acquire() + # check if inflight rollouts is full + await sem.acquire() + # wait for rollout to be permitted + await self._rollout_permitted.wait() + + # dispatch rollout + asyncio.create_task(_dispatch_one_prompt(prompt)) epoch += 1 log.info("rollout_pump: completed %d epoch(s)", epoch) From 4942d2941b7a9b504a261503e8ac1ac86e42c0f8 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 14 Jun 2026 00:57:48 -0700 Subject: [PATCH 05/44] squash entrypoint + fix (f335c92 -> 57f8eb2) Signed-off-by: Yuki Huang update functional test Signed-off-by: Yuki Huang --- .../grpo_math_1B_single_controller.yaml | 352 ++++++++++++++++ examples/run_grpo_single_controller.py | 116 +++++ .../algorithms/async_utils/replay_buffer.py | 13 +- nemo_rl/algorithms/single_controller.py | 396 +++++++----------- .../single_controller_utils/__init__.py | 35 ++ .../single_controller_utils/config.py | 79 ++++ .../single_controller_utils/setup.py | 369 ++++++++++++++++ nemo_rl/experience/rollout_manager.py | 6 + nemo_rl/models/policy/tq_policy.py | 6 +- .../policy/workers/megatron_policy_worker.py | 29 +- .../functional/L1_Functional_Tests_GRPO_3.sh | 1 + tests/functional/grpo_dp_single_controller.sh | 51 +++ .../single_controller/test_rollout_pump.py | 66 ++- .../test_single_controller_dryrun.py | 153 +++---- .../test_single_controller_setup.py | 260 ++++++++++++ 15 files changed, 1560 insertions(+), 372 deletions(-) create mode 100644 examples/configs/grpo_math_1B_single_controller.yaml create mode 100644 examples/run_grpo_single_controller.py create mode 100644 nemo_rl/algorithms/single_controller_utils/__init__.py create mode 100644 nemo_rl/algorithms/single_controller_utils/config.py create mode 100644 nemo_rl/algorithms/single_controller_utils/setup.py create mode 100755 tests/functional/grpo_dp_single_controller.sh create mode 100644 tests/unit/single_controller/test_single_controller_setup.py diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml new file mode 100644 index 00000000000..2054a51dbc1 --- /dev/null +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -0,0 +1,352 @@ +# GRPO via SingleController (async-RL) — mirrors grpo_math_1B.yaml with +# data_plane.enabled=true and a top-level async_rl: section holding the +# SC-specific runtime knobs. +grpo: + num_prompts_per_step: 32 + num_generations_per_prompt: 16 + max_rollout_turns: 1 + max_num_epochs: 1 + max_num_steps: 1000000 + normalize_rewards: true + use_leave_one_out_baseline: true + val_period: 10 + val_at_start: false + val_at_end: false + overlong_filtering: false + advantage_clip_low: null + advantage_clip_high: null + max_val_samples: 256 + val_batch_size: 256 + seed: 42 + use_dynamic_sampling: false + dynamic_sampling_max_gen_batches: 10 + batch_multiplier: 1 + reward_shaping: + enabled: false + overlong_buffer_length: 128 + overlong_buffer_penalty: 1 + max_response_length: ${policy.max_total_sequence_length} + stop_properly_penalty_coef: null + + adv_estimator: + name: "grpo" + normalize_rewards: ${grpo.normalize_rewards} + use_leave_one_out_baseline: ${grpo.use_leave_one_out_baseline} + minus_baseline: true + reward_scaling: + enabled: false + source_min: 0.0 + source_max: 1.0 + target_min: 0.0 + target_max: 1.0 + seq_logprob_error_threshold: null + invalid_tool_call_advantage: null + malformed_thinking_advantage: null + + async_grpo: + enabled: true + max_trajectory_age_steps: 1 + in_flight_weight_updates: false + recompute_kv_cache_after_weight_updates: false + +loss_fn: + reference_policy_kl_penalty: 0.01 + reference_policy_kl_type: "k3" + kl_input_clamp_value: 20.0 + kl_output_clamp_value: 10.0 + ratio_clip_min: 0.2 + ratio_clip_max: 0.2 + ratio_clip_c: null + use_on_policy_kl_approximation: false + use_importance_sampling_correction: false + truncated_importance_sampling_type: null + truncated_importance_sampling_ratio: null + truncated_importance_sampling_ratio_min: null + sequence_level_importance_ratios: false + token_level_loss: true + force_on_policy_ratio: false + use_kl_in_reward: false + disable_ppo_ratio: false + positive_example_nll_weight: 0.0 + +checkpointing: + enabled: true + checkpoint_dir: "results/grpo-single-controller" + metric_name: "val:accuracy" + higher_is_better: true + keep_top_k: 3 + save_period: 10 + checkpoint_must_save_by: null + model_save_format: "safetensors" + save_consolidated: false + save_optimizer: true + +policy: + model_name: "Qwen/Qwen2.5-1.5B" + tokenizer: + name: ${policy.model_name} + chat_template_kwargs: null + hf_config_overrides: {} + train_global_batch_size: 512 + train_micro_batch_size: 4 + generation_batch_size: 32 + logprob_batch_size: ${policy.train_micro_batch_size} + max_total_sequence_length: 512 + precision: "bfloat16" + logprob_chunk_size: null + offload_optimizer_for_logprob: false + + dtensor_cfg: + _v2: true + enabled: false + cpu_offload: False + sequence_parallel: false + activation_checkpointing: false + tensor_parallel_size: 1 + context_parallel_size: 1 + custom_parallel_plan: null + automodel_kwargs: {} + lora_cfg: + enabled: False + target_modules: [] + exclude_modules: [] + match_all_linear: true + dim: 8 + alpha: 32 + dropout: 0.0 + dropout_position: "post" + lora_A_init: "xavier" + use_triton: true + + megatron_cfg: + enabled: true + force_reconvert_from_hf: False + empty_unused_memory_level: 1 + activation_checkpointing: false + recompute_granularity: "full" + recompute_modules: null + tensor_model_parallel_size: 1 + expert_tensor_parallel_size: 1 + expert_model_parallel_size: 1 + pipeline_model_parallel_size: 1 + num_layers_in_first_pipeline_stage: null + num_layers_in_last_pipeline_stage: null + context_parallel_size: 1 + pipeline_dtype: ${policy.precision} + sequence_parallel: false + freeze_moe_router: true + moe_router_dtype: "fp64" + moe_router_load_balancing_type: "none" + moe_router_bias_update_rate: 0.0 + moe_permute_fusion: true + apply_rope_fusion: True + bias_activation_fusion: True + defer_fp32_logits: False + moe_per_layer_logging: False + moe_enable_deepep: false + moe_token_dispatcher_type: "alltoall" + moe_shared_expert_overlap: false + gradient_accumulation_fusion: false + peft: + enabled: false + target_modules: [] + exclude_modules: [] + dim: 8 + alpha: 32 + dropout: 0.0 + dropout_position: "post" + lora_A_init_method: "xavier" + lora_B_init_method: "zero" + a2a_experimental: false + lora_dtype: None + optimizer: + optimizer: "adam" + lr: 5.0e-6 + min_lr: 5.0e-7 + weight_decay: 0.01 + bf16: true + fp16: false + params_dtype: "float32" + adam_beta1: 0.9 + adam_beta2: 0.999 + adam_eps: 1e-8 + sgd_momentum: 0.9 + use_distributed_optimizer: true + use_precision_aware_optimizer: true + clip_grad: ${policy.max_grad_norm} + optimizer_cpu_offload: false + optimizer_offload_fraction: 0.0 + scheduler: + start_weight_decay: ${policy.megatron_cfg.optimizer.weight_decay} + end_weight_decay: ${policy.megatron_cfg.optimizer.weight_decay} + weight_decay_incr_style: "constant" + lr_decay_style: "constant" + lr_decay_iters: 1000 + lr_warmup_iters: 13 + lr_warmup_init: 5.0e-7 + distributed_data_parallel_config: + grad_reduce_in_fp32: false + overlap_grad_reduce: true + overlap_param_gather: true + use_custom_fsdp: false + data_parallel_sharding_strategy: "optim_grads_params" + fp8_cfg: + enabled: false + fp8: "e4m3" + fp8_recipe: "blockwise" + fp8_param: false + env_vars: null + + draft: + enabled: false + model_name: null + loss_weight: 0.1 + num_layers: null + aux_layer_indices: null + + dynamic_batching: + enabled: False + train_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.train_micro_batch_size}} + logprob_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.logprob_batch_size}} + sequence_length_round: 64 + + sequence_packing: + enabled: True + train_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.train_micro_batch_size}} + logprob_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.logprob_batch_size}} + algorithm: "modified_first_fit_decreasing" + sequence_length_round: 64 + + make_sequence_length_divisible_by: ${policy.dtensor_cfg.tensor_parallel_size} + max_grad_norm: 1.0 + + optimizer: + name: "torch.optim.AdamW" + kwargs: + lr: 5.0e-6 + weight_decay: 0.01 + betas: [0.9, 0.999] + eps: 1e-8 + + scheduler: + - name: "torch.optim.lr_scheduler.LinearLR" + kwargs: + start_factor: 0.1 + end_factor: 1.0 + total_iters: 50 + - name: "torch.optim.lr_scheduler.ConstantLR" + kwargs: + factor: 1.0 + total_iters: 10000000000 + - milestones: [50] + + generation: + port_range_low: 11001 + port_range_high: 15000 + backend: "vllm" + max_new_tokens: ${policy.max_total_sequence_length} + temperature: 1.0 + top_p: 1.0 + top_k: null + stop_token_ids: null + stop_strings: null + mcore_generation_config: + buffer_size_gb: 10 + num_cuda_graphs: 4 + block_size_tokens: 256 + use_cuda_graphs_for_non_decode_steps: true + enable_chunked_prefill: true + unified_memory_level: 0 + max_tokens: 16384 + vllm_cfg: + async_engine: true + precision: ${policy.precision} + kv_cache_dtype: "auto" + tensor_parallel_size: 1 + pipeline_parallel_size: 1 + expert_parallel_size: 1 + gpu_memory_utilization: 0.6 + max_model_len: ${policy.max_total_sequence_length} + enforce_eager: False + use_tqdm: true + use_deep_gemm: False + num_last_layers_in_bf16: 0 + num_first_layers_in_bf16: 0 + enable_vllm_metrics_logger: true + vllm_metrics_logger_interval: 0.5 + vllm_kwargs: {} + colocated: + enabled: false + resources: + gpus_per_node: 1 + num_nodes: 1 + +data: + max_input_seq_length: ${policy.max_total_sequence_length} + shuffle: true + num_workers: 1 + use_multiple_dataloader: false + train: + dataset_name: OpenMathInstruct-2 + split_validation_size: 0.05 + seed: ${grpo.seed} + validation: null + default: + prompt_file: "examples/prompts/cot.txt" + system_prompt_file: null + processor: "math_hf_data_processor" + env_name: "math" + +env: + math: + num_workers: 8 + math_verify_impl: "hf_math_verify" + +logger: + log_dir: "logs" + num_val_samples_to_print: 0 + wandb_enabled: false + tensorboard_enabled: false + mlflow_enabled: false + swanlab_enabled: false + monitor_gpus: true + wandb: + project: "grpo-dev" + name: "grpo-single-controller-dev" + swanlab: + project: "grpo-dev" + name: "grpo-single-controller-dev" + tensorboard: {} + mlflow: + experiment_name: "grpo-dev" + run_name: "grpo-single-controller-dev" + tracking_uri: "http://localhost:5000" + gpu_monitoring: + collection_interval: 10 + flush_interval: 10 + +# TransferQueue data plane — required by the SingleController path. +data_plane: + enabled: true + impl: transfer_queue + backend: "simple" + storage_capacity: 1000000 + num_storage_units: 2 + claim_meta_poll_interval_s: 0.5 + global_segment_size: 549755813888 + local_buffer_size: 68719476736 + +# SC-specific async-RL runtime knobs. +async_rl: + max_weight_staleness_versions: 1 + min_prompt_groups_per_batch: 2 + target_prompt_groups_per_step: null # falls back to min_prompt_groups_per_batch + batch_selection_strategy: "strict_on_policy" # or "staleness_window" + max_inflight_prompts: 8 + max_buffered_rollouts: 8 + +cluster: + gpus_per_node: 2 + num_nodes: 1 + master_port_range_low: 25000 + master_port_range_high: 28000 diff --git a/examples/run_grpo_single_controller.py b/examples/run_grpo_single_controller.py new file mode 100644 index 00000000000..b1c22ee5bfa --- /dev/null +++ b/examples/run_grpo_single_controller.py @@ -0,0 +1,116 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Async GRPO launcher driven by the SingleController actor. + +Builds the full SC bundle driver-side via single_controller_utils.setup and hands it +to SingleControllerActor. Mirrors run_grpo.py for config loading so the same YAML +files apply. data_plane.enabled=true is mandatory. +""" + +import argparse +import os +import pprint + +import ray +from omegaconf import OmegaConf + +from nemo_rl.algorithms.single_controller import SingleControllerActor +from nemo_rl.algorithms.single_controller_utils import MasterConfig, setup +from nemo_rl.algorithms.utils import get_tokenizer +from nemo_rl.distributed.virtual_cluster import init_ray +from nemo_rl.models.generation import configure_generation_config +from nemo_rl.utils.config import ( + load_config, + parse_hydra_overrides, + register_omegaconf_resolvers, +) +from nemo_rl.utils.logger import get_next_experiment_dir + + +def parse_args() -> tuple[argparse.Namespace, list[str]]: + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Run async GRPO training via SingleController" + ) + parser.add_argument( + "--config", type=str, default=None, help="Path to YAML config file" + ) + args, overrides = parser.parse_known_args() + return args, overrides + + +def main() -> None: + """Main entry point.""" + register_omegaconf_resolvers() + args, overrides = parse_args() + + if not args.config: + args.config = os.path.join( + os.path.dirname(__file__), + "configs", + "grpo_math_1B_single_controller.yaml", + ) + + config = load_config(args.config) + print(f"Loaded configuration from: {args.config}") + + if overrides: + print(f"Overrides: {overrides}") + config = parse_hydra_overrides(config, overrides) + + config = OmegaConf.to_container(config, resolve=True) + config = MasterConfig(**config) + print("Applied CLI overrides") + + dp_cfg = config.data_plane + if not dp_cfg.get("enabled", False): + raise ValueError( + "run_grpo_single_controller requires data_plane.enabled=true. " + "Use examples/run_grpo.py for the legacy / sync paths." + ) + + print("Final config:") + pprint.pprint(config) + + config.logger["log_dir"] = get_next_experiment_dir(config.logger["log_dir"]) + print(f"📊 Using log directory: {config.logger['log_dir']}") + if config.checkpointing["enabled"]: + print( + f"📊 Using checkpoint directory: {config.checkpointing['checkpoint_dir']}" + ) + + init_ray() + + tokenizer = get_tokenizer(config.policy["tokenizer"]) + assert config.policy["generation"] is not None, ( + "A generation config is required for SC-driven async GRPO" + ) + has_refit_draft_weights = bool(config.policy["draft"]["enabled"]) + config.policy["generation"] = configure_generation_config( + config.policy["generation"], + tokenizer, + has_refit_draft_weights=has_refit_draft_weights, + ) + + bundle = setup(config, tokenizer) + + print("🚀 Launching SingleControllerActor") + sc = SingleControllerActor.remote(master_config=config, bundle=bundle) + result = ray.get(sc.run.remote()) + print(f"SC run complete: {result}") + + +if __name__ == "__main__": + main() diff --git a/nemo_rl/algorithms/async_utils/replay_buffer.py b/nemo_rl/algorithms/async_utils/replay_buffer.py index 62cf0b5f420..b782e0ec793 100644 --- a/nemo_rl/algorithms/async_utils/replay_buffer.py +++ b/nemo_rl/algorithms/async_utils/replay_buffer.py @@ -601,7 +601,7 @@ async def add( sample_ids, fields, tags = pack_payload( train_batch, weight_version=weight_version, group_id=group_id ) - meta = await self._call_dp( + await self._call_dp( "put_samples", sample_ids=sample_ids, partition_id=self._partition_id, @@ -609,6 +609,17 @@ async def add( tags=tags, ) + # mirrors kv_first_write + lengths = train_batch["input_lengths"] + meta = KVBatchMeta( + partition_id=self._partition_id, + task_name="train", + sample_ids=list(sample_ids), + fields=list(fields.keys()), + sequence_lengths=[int(s) for s in lengths.tolist()], + tags=[dict(t) for t in tags], + ) + self.meta_list.append(meta) self.weight_list.append(weight_version) return meta diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 49e9521ddb9..afc7b9bb50d 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -34,78 +34,22 @@ from __future__ import annotations import asyncio -import logging import time -from dataclasses import dataclass, field -from typing import Any, Literal, Optional +from typing import Any import ray import torch from tensordict import TensorDict -from torchdata.stateful_dataloader import StatefulDataLoader -from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler +from nemo_rl.algorithms.single_controller_utils.config import ( + AdvantageConfig, + MasterConfig, + WeightSyncConfig, +) +from nemo_rl.algorithms.single_controller_utils.setup import SingleControllerBundle from nemo_rl.data.interfaces import DatumSpec from nemo_rl.data_plane import KVBatchMeta -from nemo_rl.environments.interfaces import EnvironmentInterface -from nemo_rl.experience.rollout_manager import RolloutManager - -log = logging.getLogger(__name__) - - -@dataclass -class SingleControllerConfig: - """Configuration for SingleController.""" - - # Staleness - max_weight_staleness_versions: int = 1 - min_prompt_groups_per_batch: int = 2 - target_prompt_groups_per_step: Optional[int] = None - generations_per_prompt: int = 4 - batch_selection_strategy: Literal[ - "strict_on_policy", - "staleness_window", - ] = "strict_on_policy" - - # Concurrency limits - max_inflight_prompts: int = 8 - max_buffered_rollouts: int = 8 # _buffer_capacity semaphore size - - # Training - max_train_steps: int = 10 - # Cap on dataloader passes; None means unbounded (cycle until cancelled). - max_num_epochs: Optional[int] = None - - # DataPlane partition - partition_id: str = "rollout_data" - - # Advantage calculation - advantage_enabled: bool = False - advantage_output_field: str = "advantages" - advantage_prompt_ids_field: str = "prompt_ids_for_adv" - advantage_reward_field: str = "total_reward" - advantage_token_mask_field: str = "token_mask" - advantage_sample_mask_field: str = "sample_mask" - advantage_repeated_batch_fields: list[str] = field(default_factory=list) - advantage_policy_logprobs_field: str | None = None - advantage_reference_logprobs_field: str | None = None - - # Diagnostics - diagnostics: bool = False - - # Weight transport backend ("stub" for dry-run, "nccl" for production) - weight_transport: str = "stub" - weight_nccl_addr: str = "127.0.0.1" - weight_nccl_port: Optional[int] = None - - # Rollout config. Read only when SC builds RolloutManager itself. - rollout_max_seq_len: int = 1024 - rollout_max_turns: Optional[int] = None - use_nemo_gym: bool = False - - # Extra fields passed through to avoid TypedDict issues - extra: dict = field(default_factory=dict) @ray.remote(num_cpus=1, num_gpus=0) # pragma: no cover @@ -122,94 +66,63 @@ class SingleControllerActor: def __init__( self, - cfg: SingleControllerConfig, - dp_client: Any, - gen_handle: Any, - trainer_handle: Any, - env_handles: dict[str, EnvironmentInterface], - # TODO: move into SC's setup phase - dataloader: StatefulDataLoader, - weight_synchronizer: Any, - advantage_estimator: Any | None = None, - tokenizer: Any | None = None, - # TODO: remove the rollout_manager / tq_buffer overrides once SC's - # setup phase owns construction; today they let the dry-run test - # share one buffer + manager instance with SC. - rollout_manager: RolloutManager | None = None, - tq_buffer: TQReplayBuffer | None = None, + master_config: MasterConfig, + bundle: SingleControllerBundle, ) -> None: - import logging as _logging + """Initialize the SingleController actor. - _logging.basicConfig( - level=_logging.INFO, - format="[%(asctime)s] %(levelname)s %(filename)s:%(lineno)d: %(message)s", - ) - - self._cfg = cfg - self._dp_client = dp_client - self._gen = gen_handle - self._trainer = trainer_handle - self._dataloader = dataloader - self._weight_synchronizer = weight_synchronizer - self._advantage_estimator = advantage_estimator - - if cfg.advantage_enabled and self._advantage_estimator is None: - raise ValueError( - "advantage_enabled=True requires an advantage_estimator instance" + Args: + master_config: SC MasterConfig. + bundle: Pre-built bundle from single_controller_utils.setup. Tests can + construct a bundle by hand (or with fakes) to bypass the real factories. + """ + self._advantage_cfg = AdvantageConfig() + self._weight_sync_cfg = WeightSyncConfig() + self._partition_id: str = bundle.partition_id + self._diagnostics: bool = False + + self._master_config = master_config + self._async_cfg = master_config.async_rl + self._dp_client = bundle.dp_client + self._gen = bundle.gen_handle + self._trainer = bundle.trainer_handle + self._dataloader = bundle.dataloader + self._weight_synchronizer = bundle.weight_synchronizer + self._advantage_estimator = bundle.advantage_estimator + self._loss_fn = bundle.loss_fn + self._buffer = bundle.tq_buffer + self._rollout_manager = bundle.rollout_manager + # Rebind so writer and sampler share one buffer instance even + # when Ray deserializes rollout_manager and tq_buffer separately. + self._rollout_manager._tq_buffer = self._buffer + + # Pin clusters so RayVirtualCluster.__del__ doesn't remove the PGs. + self._train_cluster = bundle.train_cluster + self._inference_cluster = bundle.inference_cluster + + if self._async_cfg.target_prompt_groups_per_step is None: + self._async_cfg.target_prompt_groups_per_step = ( + self._async_cfg.min_prompt_groups_per_batch ) - - if cfg.target_prompt_groups_per_step is None: - cfg.target_prompt_groups_per_step = cfg.min_prompt_groups_per_batch - if cfg.target_prompt_groups_per_step < cfg.min_prompt_groups_per_batch: + if ( + self._async_cfg.target_prompt_groups_per_step + < self._async_cfg.min_prompt_groups_per_batch + ): raise ValueError( - f"target_prompt_groups_per_step ({cfg.target_prompt_groups_per_step}) " - f"must be >= min_prompt_groups_per_batch ({cfg.min_prompt_groups_per_batch})" + f"target_prompt_groups_per_step ({self._async_cfg.target_prompt_groups_per_step}) " + f"must be >= min_prompt_groups_per_batch ({self._async_cfg.min_prompt_groups_per_batch})" ) - pad_id = int(getattr(tokenizer, "pad_token_id", 0) or 0) - if tq_buffer is None: - self._buffer = TQReplayBuffer( - dp_client, - partition_id=cfg.partition_id, - pad_value_dict={"token_ids": pad_id}, - ) - else: - self._buffer = tq_buffer - - if rollout_manager is None: - self._rollout_manager = RolloutManager( - tokenizer=tokenizer, - env_handles=env_handles, - num_generations_per_prompt=cfg.generations_per_prompt, - max_seq_len=cfg.rollout_max_seq_len, - max_rollout_turns=cfg.rollout_max_turns, - use_nemo_gym=cfg.use_nemo_gym, - policy_generation=gen_handle, - tq_buffer=self._buffer, - ) - else: - self._rollout_manager = rollout_manager - # Ray serializes kwargs as separate cloudpickle blobs, so a - # rollout_manager and tq_buffer passed together as `.remote()` - # args deserialize as distinct buffer instances inside the actor. - # Rebind so the rollout writer and sampler share one buffer. - self._rollout_manager._tq_buffer = self._buffer - - # Initialize sampler - assert cfg.batch_selection_strategy in [ - "strict_on_policy", - "staleness_window", - ], f"Unknown batch_selection_strategy: {cfg.batch_selection_strategy}" - - if cfg.batch_selection_strategy == "strict_on_policy": - cfg.max_weight_staleness_versions = 0 + if self._async_cfg.batch_selection_strategy == "strict_on_policy": + self._async_cfg.max_weight_staleness_versions = 0 print( - "Using strict_on_policy, auto setting max_weight_staleness_versions to 0." + "Using strict_on_policy, auto setting max_weight_staleness_versions to 0.", + flush=True, ) self._sampler = StalenessSampler( self._buffer, - max_staleness_versions=cfg.max_weight_staleness_versions, + max_staleness_versions=self._async_cfg.max_weight_staleness_versions, ) # ── asyncio state ────────────────────────────────────────────────── @@ -224,19 +137,20 @@ def __init__( # Acquired before each rollout dispatch; released when the buffer # drops a group (sampler.evict or post-train buffer.remove). self._buffer_capacity: asyncio.Semaphore = asyncio.Semaphore( - cfg.max_buffered_rollouts + self._async_cfg.max_buffered_rollouts ) self._trainer_version: int = 0 self._train_steps: int = 0 self._step_consumed_sample_ids: list[str] = [] - log.info( - "SingleControllerActor: staleness_cap=%d buffer=%d inflight=%d transport=%s", - cfg.max_weight_staleness_versions, - cfg.max_buffered_rollouts, - cfg.max_inflight_prompts, - cfg.weight_transport, + print( + f"SingleControllerActor: " + f"staleness_cap={self._async_cfg.max_weight_staleness_versions} " + f"buffer={self._async_cfg.max_buffered_rollouts} " + f"inflight={self._async_cfg.max_inflight_prompts} " + f"transport={self._weight_sync_cfg.transport}", + flush=True, ) # ── public API ───────────────────────────────────────────────────────── @@ -275,29 +189,6 @@ async def _ray_get(self, obj_ref: Any) -> Any: """Await a Ray ObjectRef without blocking the asyncio event loop.""" return await obj_ref - async def _reap_in_flight_nonblocking( - self, refs: list[ray.ObjectRef] - ) -> list[ray.ObjectRef]: - """Drain completed refs without blocking; return still-pending refs. - - Uses ``asyncio.wait`` with ``timeout=0`` so Ray ObjectRefs are checked - through their awaitable interface (which is accurate in async actors). - ``ray.wait(timeout=0)`` does not always reflect cross-process ref - readiness from an async actor, so we avoid it here. - """ - if not refs: - return [] - ref_to_task = {ref: asyncio.ensure_future(ref) for ref in refs} - await asyncio.wait(ref_to_task.values(), timeout=0.05) - pending: list[ray.ObjectRef] = [] - for ref, task in ref_to_task.items(): - if task.done(): - task.result() # surface exceptions; payload ignored - else: - task.cancel() - pending.append(ref) - return pending - async def _call_dp(self, method_name: str, **kwargs) -> Any: """Call a DataPlaneClient method or a Ray actor exposing that method.""" method = getattr(self._dp_client, method_name) @@ -311,6 +202,8 @@ async def _call_dp(self, method_name: str, **kwargs) -> Any: # ── the three pumps + advantage helper ──────────────────────────────── + # TODO @yukih: rollout_pump only gates on buffer_capacity, not on the current step's group quota. + # e.g. max_staleness_versions=0, gbs=16, groups generated past the step's 16 become stale at the next weight sync and get evicted — wasted GPU. async def _rollout_pump(self) -> None: """Continuously dispatch rollout tasks until cancellation. @@ -323,31 +216,31 @@ async def _rollout_pump(self) -> None: TQReplayBuffer.add (→ dp_client.put_samples + meta append) 5. Decrement _inflight_rollouts """ - sem = asyncio.Semaphore(self._cfg.max_inflight_prompts) - log.info("rollout_pump: starting") + sem = asyncio.Semaphore(self._async_cfg.max_inflight_prompts) + print("rollout_pump: starting", flush=True) async def _dispatch_one_prompt(prompt: DatumSpec) -> None: self._inflight_rollouts += 1 try: await self._rollout_manager.generate_and_push(prompt) - if self._cfg.diagnostics: + if self._diagnostics: content = "" for i in range(len(prompt["message_log"])): if prompt["message_log"][i]["role"] == "user": content = prompt["message_log"][i]["content"] break - log.info(" rollout done for prompt='%s...'", content[:20]) + print(f" rollout done for prompt='{content[:20]}...'", flush=True) finally: self._inflight_rollouts -= 1 sem.release() # TODO: limit max_train_steps to max_num_epochs * len(dataloader) when setup - max_epochs = self._cfg.max_num_epochs + max_epochs = self._master_config.grpo["max_num_epochs"] epoch = 0 while max_epochs is None or epoch < max_epochs: for prompt_batch in self._dataloader: for prompt_idx in range(prompt_batch.size): - prompt: DatumSpec = { + prompt: DatumSpec = { # type: ignore k: v[prompt_idx] for k, v in prompt_batch.items() } @@ -362,7 +255,7 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: asyncio.create_task(_dispatch_one_prompt(prompt)) epoch += 1 - log.info("rollout_pump: completed %d epoch(s)", epoch) + print(f"rollout_pump: completed {epoch} epoch(s)", flush=True) async def _train_pump(self) -> None: """Drain stale groups, sample, train, drop. @@ -373,41 +266,43 @@ async def _train_pump(self) -> None: buffer; DP rows survive so the trainer can read them. Already trainable — buffer wrote training-shaped rows at rollout time. 3. _advantage_pump(train_meta). - 4. trainer.train_on_meta(train_meta, dp_client). + 4. trainer.train_microbatch_from_meta + finish_train_step. 5. dp_client.clear_samples on consumed sample_ids; release _buffer_capacity per dropped group, then sync. """ - logprobs_required = ( - self._cfg.advantage_policy_logprobs_field is not None - or self._cfg.advantage_reference_logprobs_field is not None - ) + adv_cfg = self._advantage_cfg + grpo_cfg = self._master_config.grpo + + # TODO: fix the compute_prev_logprobs and compute_reference_logprobs logic + compute_prev_logprobs = adv_cfg.policy_logprobs_field is not None + compute_reference_logprobs = adv_cfg.reference_logprobs_field is not None - while self._train_steps < self._cfg.max_train_steps: + while self._train_steps < grpo_cfg["max_num_steps"]: step_id = f"sc-step-{self._train_steps:06d}" # __init__ coerces None → min_prompt_groups_per_batch (int); # the assert narrows the Optional[int] type for pyrefly. - assert self._cfg.target_prompt_groups_per_step is not None - target_groups: int = self._cfg.target_prompt_groups_per_step + assert self._async_cfg.target_prompt_groups_per_step is not None + target_groups: int = self._async_cfg.target_prompt_groups_per_step groups_dispatched = 0 - in_flight: list[ray.ObjectRef] = [] step_open = False - evicted = await self._sampler.evict( - current_train_weight=self._trainer_version, - ) - if evicted: - log.info(" evicted %d stale prompt group(s)", evicted) - for _ in range(evicted): - self._buffer_capacity.release() - while groups_dispatched < target_groups: await asyncio.sleep(0) + # evict stale groups + evicted = await self._sampler.evict( + current_train_weight=self._trainer_version, + ) + if evicted: + print(f" evicted {evicted} stale prompt group(s)", flush=True) + for _ in range(evicted): + self._buffer_capacity.release() + # TODO @yukih: wait train pump merged, now always return min_prompt_groups_per_batch # need to add a max_prompt_groups_per_batch train_meta, num_groups = await self._sampler.select( current_train_weight=self._trainer_version, - min_prompt_groups=self._cfg.min_prompt_groups_per_batch, + min_prompt_groups=self._async_cfg.min_prompt_groups_per_batch, ) if train_meta is None: @@ -417,58 +312,55 @@ async def _train_pump(self) -> None: for _ in range(num_groups): self._buffer_capacity.release() - if logprobs_required: - await self._ray_get( - self._trainer.prepare_logprobs_from_meta.remote(train_meta) - ) + # Compute prev_logprobs / ref_logprobs + if compute_prev_logprobs: + self._trainer.get_logprobs_from_meta(train_meta) + + if compute_reference_logprobs: + self._trainer.get_reference_policy_logprobs_from_meta(train_meta) train_meta = await self._advantage_pump(train_meta) if not step_open: - await self._ray_get(self._trainer.begin_train_step.remote(step_id)) + self._trainer.begin_train_step(step_id, loss_fn=self._loss_fn) step_open = True - future = self._trainer.train_microbatch_from_meta.remote( - step_id, train_meta - ) - in_flight.append(future) + # Driver-side TQPolicy blocks until worker results land; we drop + # the per-microbatch dict and surface aggregated metrics from + # finish_train_step instead. + self._trainer.train_microbatch_from_meta(step_id, train_meta) groups_dispatched += num_groups self._step_consumed_sample_ids.extend(train_meta.sample_ids) - in_flight = await self._reap_in_flight_nonblocking(in_flight) - - for fut in in_flight: - await self._ray_get(fut) - if not step_open: - log.info("train_pump: rollout exhausted before any group ready") + print( + "train_pump: rollout exhausted before any group ready", flush=True + ) break - result = await self._ray_get( - self._trainer.finish_train_step.remote(step_id) - ) + # TODO: add log + result = self._trainer.finish_train_step(step_id) consumed_ids = list(self._step_consumed_sample_ids) self._step_consumed_sample_ids = [] await self._call_dp( "clear_samples", sample_ids=list(consumed_ids), - partition_id=self._cfg.partition_id, + partition_id=self._partition_id, ) - self._trainer_version = result["trainer_version"] min_sample_version = min(t["weight_version"] for t in train_meta.tags) # type: ignore lag = self._trainer_version - min_sample_version - log.info( - "train step %d/%d trainer_v=%d lag=%d batch_size=%d", - self._train_steps + 1, - self._cfg.max_train_steps, - self._trainer_version, - lag, - len(consumed_ids), + print( + f"train step {self._train_steps + 1}/{grpo_cfg['max_num_steps']} " + f"trainer_v={self._trainer_version} " + f"lag={lag} " + f"batch_size={len(consumed_ids)}", + flush=True, ) - await self._sync_weights() + self._trainer_version += 1 self._train_steps += 1 + await self._sync_weights() async def _sync_weights(self) -> None: """Drain in-flight rollouts then synchronize weights. @@ -491,17 +383,18 @@ async def _sync_weights(self) -> None: await asyncio.sleep(0.005) drain_elapsed = time.monotonic() - drain_start - log.info( - " _sync_weights: drained in %.3fs, syncing weights v%d", - drain_elapsed, - self._trainer_version, + print( + f" _sync_weights: drained in {drain_elapsed:.3f}s, " + f"syncing weights v{self._trainer_version}", + flush=True, ) t0 = time.monotonic() - await self._weight_synchronizer.sync_weights(self._trainer_version) + # TODO: currently sync_weights is not implemented, comment out for now + # await self._weight_synchronizer.sync_weights() elapsed = time.monotonic() - t0 - log.info(" _sync_weights: sync done in %.3fs", elapsed) + print(f" _sync_weights: sync done in {elapsed:.3f}s", flush=True) self._rollout_manager.set_weight_version(self._trainer_version) self._rollout_permitted.set() @@ -514,9 +407,9 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: only the configured advantage input columns and writes the computed ``advantages`` column back under the same ``sample_ids``. """ - if not self._cfg.advantage_enabled: + if self._advantage_estimator is None: return meta - assert self._advantage_estimator is not None + adv_cfg = self._advantage_cfg data = await self._call_dp( "get_samples", @@ -525,34 +418,34 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: select_fields=self._advantage_input_fields(), ) - prompt_ids = _tensor_field(data, self._cfg.advantage_prompt_ids_field) + prompt_ids = _tensor_field(data, adv_cfg.prompt_ids_field) rewards = _squeeze_trailing_unit_dim( - _tensor_field(data, self._cfg.advantage_reward_field) + _tensor_field(data, adv_cfg.reward_field) ).float() - token_mask = _tensor_field(data, self._cfg.advantage_token_mask_field).float() + token_mask = _tensor_field(data, adv_cfg.token_mask_field).float() sample_mask = _squeeze_trailing_unit_dim( - _tensor_field(data, self._cfg.advantage_sample_mask_field) + _tensor_field(data, adv_cfg.sample_mask_field) ).float() mask = token_mask * sample_mask.unsqueeze(-1) repeated_batch: dict[str, torch.Tensor] = { "total_reward": rewards, } - for field_name in self._cfg.advantage_repeated_batch_fields: + for field_name in adv_cfg.repeated_batch_fields: repeated_batch[field_name] = _squeeze_trailing_unit_dim( _tensor_field(data, field_name) ) kwargs: dict[str, torch.Tensor] = {} - if self._cfg.advantage_policy_logprobs_field is not None: + if adv_cfg.policy_logprobs_field is not None: kwargs["logprobs_policy"] = _tensor_field( data, - self._cfg.advantage_policy_logprobs_field, + adv_cfg.policy_logprobs_field, ) - if self._cfg.advantage_reference_logprobs_field is not None: + if adv_cfg.reference_logprobs_field is not None: kwargs["logprobs_reference"] = _tensor_field( data, - self._cfg.advantage_reference_logprobs_field, + adv_cfg.reference_logprobs_field, ) advantages = self._advantage_estimator.compute_advantage( @@ -569,25 +462,26 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: partition_id=meta.partition_id, fields=_fields_for_put( meta, - {self._cfg.advantage_output_field: advantages}, + {adv_cfg.output_field: advantages}, ), ) - return meta.with_fields([self._cfg.advantage_output_field]) + return meta.with_fields([adv_cfg.output_field]) # ── utility helpers ──────────────────────────────────────────────────── def _advantage_input_fields(self) -> list[str]: + adv_cfg = self._advantage_cfg fields = [ - self._cfg.advantage_prompt_ids_field, - self._cfg.advantage_reward_field, - self._cfg.advantage_token_mask_field, - self._cfg.advantage_sample_mask_field, - *self._cfg.advantage_repeated_batch_fields, + adv_cfg.prompt_ids_field, + adv_cfg.reward_field, + adv_cfg.token_mask_field, + adv_cfg.sample_mask_field, + *adv_cfg.repeated_batch_fields, ] - if self._cfg.advantage_policy_logprobs_field is not None: - fields.append(self._cfg.advantage_policy_logprobs_field) - if self._cfg.advantage_reference_logprobs_field is not None: - fields.append(self._cfg.advantage_reference_logprobs_field) + if adv_cfg.policy_logprobs_field is not None: + fields.append(adv_cfg.policy_logprobs_field) + if adv_cfg.reference_logprobs_field is not None: + fields.append(adv_cfg.reference_logprobs_field) return list(dict.fromkeys(fields)) diff --git a/nemo_rl/algorithms/single_controller_utils/__init__.py b/nemo_rl/algorithms/single_controller_utils/__init__.py new file mode 100644 index 00000000000..9c16687db7f --- /dev/null +++ b/nemo_rl/algorithms/single_controller_utils/__init__.py @@ -0,0 +1,35 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""SingleController utilities: config schema + setup factories.""" + +from nemo_rl.algorithms.single_controller_utils.config import ( + AdvantageConfig, + AsyncRLConfig, + MasterConfig, + WeightSyncConfig, +) +from nemo_rl.algorithms.single_controller_utils.setup import ( + SingleControllerBundle, + setup, +) + +__all__ = [ + "AdvantageConfig", + "AsyncRLConfig", + "MasterConfig", + "SingleControllerBundle", + "WeightSyncConfig", + "setup", +] diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py new file mode 100644 index 00000000000..270a7f0b823 --- /dev/null +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -0,0 +1,79 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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 __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any, Literal, Optional + +from pydantic import BaseModel, Field + +from nemo_rl.algorithms.grpo import GRPOConfig, GRPOLoggerConfig +from nemo_rl.algorithms.loss import ClippedPGLossConfig +from nemo_rl.data import DataConfig +from nemo_rl.data_plane.interfaces import DataPlaneConfig +from nemo_rl.distributed.virtual_cluster import ClusterConfig +from nemo_rl.models.policy import PolicyConfig +from nemo_rl.utils.checkpoint import CheckpointingConfig + +# ── User-facing SingleController configs ──────────────────────────────────── + + +class AsyncRLConfig(BaseModel, extra="allow"): + # Sampler / on-policy enforcement. + max_weight_staleness_versions: int = 1 + min_prompt_groups_per_batch: int = 2 + target_prompt_groups_per_step: Optional[int] = None + batch_selection_strategy: Literal[ + "strict_on_policy", + "staleness_window", + ] = "strict_on_policy" + # Pump concurrency caps. + max_inflight_prompts: int = 8 + max_buffered_rollouts: int = 8 + + +class MasterConfig(BaseModel, extra="allow"): + policy: PolicyConfig + loss_fn: ClippedPGLossConfig + env: dict[str, Any] = Field(default_factory=dict) + data: DataConfig + grpo: GRPOConfig + logger: GRPOLoggerConfig + cluster: ClusterConfig + checkpointing: CheckpointingConfig + data_plane: DataPlaneConfig + async_rl: AsyncRLConfig = Field(default_factory=AsyncRLConfig) + + +# ── Internal SingleController configs ──────────────────────────────────── + + +@dataclass +class AdvantageConfig: + output_field: str = "advantages" + prompt_ids_field: str = "prompt_ids_for_adv" + reward_field: str = "total_reward" + token_mask_field: str = "token_mask" + sample_mask_field: str = "sample_mask" + repeated_batch_fields: list[str] = field(default_factory=list) + policy_logprobs_field: Optional[str] = "prev_logprobs" + reference_logprobs_field: Optional[str] = "reference_policy_logprobs" + + +@dataclass +class WeightSyncConfig: + transport: str = "stub" + nccl_addr: str = "127.0.0.1" + nccl_port: Optional[int] = None diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py new file mode 100644 index 00000000000..c043c1154bf --- /dev/null +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -0,0 +1,369 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""Driver-side factory for the SingleController (async-RL) training path. + +setup builds the full SingleControllerBundle on the driver and the caller passes it to +SingleControllerActor.remote. Everything lives on the driver because driver-side +TQPolicy owns the worker group directly — running this inside another Ray actor nests +runtime_envs and breaks Ray's resource resolution (see the PR #2692 follow-up). +""" + +from __future__ import annotations + +from concurrent.futures import ThreadPoolExecutor +from dataclasses import dataclass +from typing import Any, Optional + +from torchdata.stateful_dataloader import StatefulDataLoader +from transformers import AutoProcessor +from transformers.tokenization_utils_base import PreTrainedTokenizerBase + +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer +from nemo_rl.algorithms.grpo import _create_advantage_estimator +from nemo_rl.algorithms.loss import ClippedPGLossFn +from nemo_rl.algorithms.loss.interfaces import LossFunction +from nemo_rl.algorithms.single_controller_utils.config import MasterConfig +from nemo_rl.data.collate_fn import rl_collate_fn +from nemo_rl.data.utils import setup_response_data +from nemo_rl.data_plane import build_data_plane_client +from nemo_rl.distributed.virtual_cluster import RayVirtualCluster +from nemo_rl.environments.interfaces import EnvironmentInterface +from nemo_rl.experience.rollout_manager import RolloutManager +from nemo_rl.models.generation.sglang import SGLangGeneration +from nemo_rl.models.generation.vllm import VllmGeneration +from nemo_rl.models.policy.tq_policy import TQPolicy +from nemo_rl.weight_sync import WeightSynchronizer, create_weight_synchronizer + + +@dataclass +class SingleControllerBundle: + """All inputs SingleControllerActor needs, built driver-side by setup(). + + Passed as a single arg to SingleControllerActor.remote so the actor's __init__ does + no construction work — every heavy object is cloudpickled in. + """ + + gen_handle: Any + trainer_handle: Any # driver-side TQPolicy + env_handles: dict[str, EnvironmentInterface] + train_cluster: RayVirtualCluster + inference_cluster: RayVirtualCluster + dp_client: Any + dataloader: StatefulDataLoader + weight_synchronizer: WeightSynchronizer + advantage_estimator: Any + loss_fn: LossFunction + rollout_manager: RolloutManager + tq_buffer: TQReplayBuffer + partition_id: str + + +def _build_clusters( + master_config: MasterConfig, +) -> tuple[RayVirtualCluster, RayVirtualCluster]: + """Allocate train + inference clusters; one shared cluster when colocated.""" + cluster_config = master_config.cluster + generation_config = master_config.policy["generation"] + colocated = generation_config["colocated"]["enabled"] + backend = generation_config["backend"] + num_nodes = cluster_config["num_nodes"] + gpus_per_node = cluster_config["gpus_per_node"] + port_range_low = cluster_config.get("master_port_range_low") + port_range_high = cluster_config.get("master_port_range_high") + + if colocated: + # Policy + generation share GPUs — one cluster. + cluster = RayVirtualCluster( + name="sc_policy_cluster", + bundle_ct_per_node_list=[gpus_per_node] * num_nodes, + use_gpus=True, + num_gpus_per_node=gpus_per_node, + max_colocated_worker_groups=1 if backend == "megatron" else 2, + port_range_low=port_range_low, + port_range_high=port_range_high, + ) + return cluster, cluster + + # Non-colocated: split node into train + inference clusters. + assert backend != "megatron", ( + "Non-colocated inference is not supported for Megatron generation backends." + ) + inference_resources = generation_config["colocated"]["resources"] + inference_gpus_per_node = inference_resources["gpus_per_node"] + inference_nodes = inference_resources["num_nodes"] or 1 + if num_nodes == 1: + train_gpus_per_node = gpus_per_node - inference_gpus_per_node + train_nodes = 1 + assert train_gpus_per_node > 0, ( + f"Not enough GPUs for training: {gpus_per_node} - {inference_gpus_per_node} = {train_gpus_per_node}" + ) + else: + train_gpus_per_node = gpus_per_node + train_nodes = num_nodes - inference_nodes + assert train_nodes > 0, ( + f"train_nodes must be > 0: {num_nodes} - {inference_nodes} = {train_nodes}" + ) + + train_cluster = RayVirtualCluster( + name="sc_train_cluster", + bundle_ct_per_node_list=[train_gpus_per_node] * train_nodes, + use_gpus=True, + num_gpus_per_node=train_gpus_per_node, + max_colocated_worker_groups=1, + port_range_low=port_range_low, + port_range_high=port_range_high, + ) + inference_cluster = RayVirtualCluster( + name="sc_inference_cluster", + bundle_ct_per_node_list=[inference_gpus_per_node] * inference_nodes, + use_gpus=True, + num_gpus_per_node=inference_gpus_per_node, + max_colocated_worker_groups=1, + port_range_low=port_range_low, + port_range_high=port_range_high, + ) + return train_cluster, inference_cluster + + +def _build_generation( + inference_cluster: RayVirtualCluster, + master_config: MasterConfig, +): + """Spin up the generation backend (vLLM or SGLang).""" + generation_config = master_config.policy["generation"] + generation_config["model_name"] = master_config.policy["model_name"] + backend = generation_config["backend"] + if backend == "vllm": + generation_config["vllm_kwargs"]["hf_overrides"] = master_config.policy.get( + "hf_config_overrides", {} + ) + gen = VllmGeneration(cluster=inference_cluster, config=generation_config) + elif backend == "sglang": + generation_config["sglang_cfg"].setdefault( + "model_path", master_config.policy["model_name"] + ) + gen = SGLangGeneration(cluster=inference_cluster, config=generation_config) + else: + raise ValueError( + f"single_controller_utils.setup only supports vllm or sglang generation; got {backend!r}" + ) + gen.finish_generation() + return gen + + +def _build_trainer( + train_cluster: RayVirtualCluster, + master_config: MasterConfig, + tokenizer, + processor, +): + """Build the TQ-mediated trainer (driver-side TQPolicy). + + Driver-side on purpose: instantiating TQPolicy inside another Ray + actor nests runtime_envs and triggers Ray's + get_accelerator_ids_for_accelerator_resource IndexError. Keep this + here until PolicyTrainerActor (PR #2692) lands. + """ + loss_config = master_config.loss_fn + init_reference_model = loss_config.reference_policy_kl_penalty > 0 + return TQPolicy( + cluster=train_cluster, + config=master_config.policy, + tokenizer=tokenizer, + processor=processor, + weights_path=None, + optimizer_path=None, + init_optimizer=True, + init_reference_model=init_reference_model, + dp_cfg=master_config.data_plane, + ) + + +def _generation_max_seq_len(generation_config) -> int: + """Return the per-backend max sequence length. + + vllm uses vllm_cfg.max_model_len; sglang uses sglang_cfg.context_length; + megatron generation has no dedicated field and routes max_new_tokens + through as max_sequence_length on the inference worker. + """ + backend = generation_config["backend"] + if backend == "vllm": + return generation_config["vllm_cfg"]["max_model_len"] + if backend == "sglang": + return generation_config["sglang_cfg"]["context_length"] + if backend == "megatron": + return generation_config["max_new_tokens"] + raise ValueError(f"Unknown generation backend: {backend!r}") + + +def _maybe_inject_megatron_train_iters( + master_config: MasterConfig, dataloader: StatefulDataLoader +) -> None: + """Mirror grpo_sync's train_iters formula for the Megatron backend. + + Megatron's LR scheduler reads train_iters at TQPolicy.__init__, so + this must run before _build_trainer. + """ + policy_config = master_config.policy + if not policy_config.get("megatron_cfg", {}).get("enabled", False): + return + grpo_config = master_config.grpo + policy_config["megatron_cfg"]["train_iters"] = min( + grpo_config["max_num_steps"], + grpo_config["max_num_epochs"] * len(dataloader), + ) + + +def setup( + master_config: MasterConfig, + tokenizer: PreTrainedTokenizerBase, + *, + processor: Optional[AutoProcessor] = None, + partition_id: str = "rollout_data", +) -> SingleControllerBundle: + """Build the full SC bundle driver-side. + + Args: + master_config: SC MasterConfig. + tokenizer: Tokenizer used by the policy. + processor: Optional AutoProcessor for VLM paths. + partition_id: TQ partition the rollout writer + sampler share. + + Returns: + SingleControllerBundle ready to be passed to SingleControllerActor. + """ + dp_cfg = master_config.data_plane + if dp_cfg is None or not dp_cfg.get("enabled", False): + raise ValueError( + "single_controller_utils.setup requires " + "master_config.data_plane.enabled=True. The async-RL " + "SingleController path is built on the TransferQueue data plane." + ) + + data_config = master_config.data + grpo_config = master_config.grpo + generation_config = master_config.policy["generation"] + assert generation_config is not None, ( + "single_controller_utils.setup requires policy.generation in master_config" + ) + + if data_config["use_multiple_dataloader"]: + raise NotImplementedError( + "single_controller_utils does not support " + "data.use_multiple_dataloader=True yet." + ) + + # ========================== + # Setup Dataset & Environments + # ========================== + # TODO: add validate dataset wiring. + dataset, _val_dataset, env_handles, _val_env_handles = setup_response_data( + tokenizer, data_config, env_configs=master_config.env + ) + dataloader = StatefulDataLoader( + dataset, + batch_size=grpo_config["num_prompts_per_step"], + shuffle=data_config["shuffle"], + collate_fn=rl_collate_fn, + drop_last=True, + num_workers=data_config["num_workers"], + ) + + _maybe_inject_megatron_train_iters(master_config, dataloader) + + # ========================== + # Setup Clusters & Workers + # ========================== + train_cluster, inference_cluster = _build_clusters(master_config) + colocated = generation_config["colocated"]["enabled"] + if colocated: + # Colocated: vLLM prefers a clean GPU at load time, so generation + # comes up before the policy. + generation = _build_generation(inference_cluster, master_config) + policy = _build_trainer(train_cluster, master_config, tokenizer, processor) + else: + # Non-colocated: generation + policy run on disjoint GPUs, so + # bring them up in parallel. + with ThreadPoolExecutor(max_workers=2) as executor: + gen_future = executor.submit( + _build_generation, inference_cluster, master_config + ) + policy_future = executor.submit( + _build_trainer, train_cluster, master_config, tokenizer, processor + ) + generation = gen_future.result() + policy = policy_future.result() + + # ========================== + # Setup Data Plane Client & Weight Sync + # ========================== + # Connect-only DP client; TQPolicy already bootstrapped the controller. + dp_client = build_data_plane_client(dp_cfg, bootstrap=False) + + backend = generation_config["backend"] + refit_buffer_size_gb = ( + generation_config.get("colocated", {}) + .get("resources", {}) + .get("refit_buffer_size_gb") + ) + # TODO: weight synchronizer not validated yet, placeholder wiring. + weight_synchronizer = create_weight_synchronizer( + policy=policy, + generation=generation, + generation_backend=backend, + colocated=colocated, + train_cluster=train_cluster, + inference_cluster=inference_cluster, + refit_buffer_size_gb=refit_buffer_size_gb, + ) + + # ========================== + # Setup Algorithm + Rollout Wiring + # ========================== + advantage_estimator = _create_advantage_estimator(master_config) + loss_fn: LossFunction = ClippedPGLossFn(master_config.loss_fn) + + pad_id = int(getattr(tokenizer, "pad_token_id", 0) or 0) + tq_buffer = TQReplayBuffer( + dp_client, + partition_id=partition_id, + pad_value_dict={"token_ids": pad_id, "input_ids": pad_id}, + ) + rollout_manager = RolloutManager( + tokenizer=tokenizer, + env_handles=env_handles, + num_generations_per_prompt=grpo_config["num_generations_per_prompt"], + max_seq_len=_generation_max_seq_len(generation_config), + max_rollout_turns=grpo_config.get("max_rollout_turns"), + policy_generation=generation, + generation_config=generation_config, + use_nemo_gym=False, + tq_buffer=tq_buffer, + ) + + return SingleControllerBundle( + gen_handle=generation, + trainer_handle=policy, + env_handles=env_handles, + train_cluster=train_cluster, + inference_cluster=inference_cluster, + dp_client=dp_client, + dataloader=dataloader, + weight_synchronizer=weight_synchronizer, + advantage_estimator=advantage_estimator, + loss_fn=loss_fn, + rollout_manager=rollout_manager, + tq_buffer=tq_buffer, + partition_id=partition_id, + ) diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 41374a13448..c2d6bd658ef 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -581,6 +581,12 @@ def _compute_rollout_metrics( return rollout_metrics +# TODO(SC): +# 1. Turn RolloutManager into a Ray actor. +# 2. Keep policy_generation driver-constructed and pass it in (don't +# build it inside the rollout actor — avoids nested Ray actors). +# 3. Construct the rollout actor in single_controller_utils.setup and +# drop the inline RolloutManager construction there. class RolloutManager: """Routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym), and pushes results to a TQReplayBuffer.""" diff --git a/nemo_rl/models/policy/tq_policy.py b/nemo_rl/models/policy/tq_policy.py index 61731f5ca50..058647ba0ad 100644 --- a/nemo_rl/models/policy/tq_policy.py +++ b/nemo_rl/models/policy/tq_policy.py @@ -491,7 +491,7 @@ def begin_train_step( gbs=batch_size, mbs=micro_batch_size, ) - self.worker_group.get_all_worker_results(futures) + ray.get(futures) def train_microbatch_from_meta( self, @@ -563,7 +563,7 @@ def finish_train_step(self, step_id: str) -> dict[str, Any]: "finish_train_step_presharded", step_id=step_id, ) - results = self.worker_group.get_all_worker_results(futures) + results = ray.get(futures) aggregated_results = _aggregate_train_results(results) if self.flops_tracker is not None: @@ -578,7 +578,7 @@ def abort_train_step(self, step_id: str) -> None: "abort_train_step_presharded", step_id=step_id, ) - self.worker_group.get_all_worker_results(futures) + ray.get(futures) if self.flops_tracker is not None: self.flops_tracker.reset() diff --git a/nemo_rl/models/policy/workers/megatron_policy_worker.py b/nemo_rl/models/policy/workers/megatron_policy_worker.py index 70253fbdcaf..94a74514131 100644 --- a/nemo_rl/models/policy/workers/megatron_policy_worker.py +++ b/nemo_rl/models/policy/workers/megatron_policy_worker.py @@ -886,6 +886,7 @@ def _split_step_state_init( "total_num_microbatches": 0, # Saved across the step so we can restore at finish/abort. "saved_grad_sync_func": None, + "saved_no_sync_func": None, "no_sync_active": False, } @@ -932,21 +933,27 @@ def begin_train_step( step_id=step_id, loss_fn=loss_fn, gbs=gbs, mbs=mbs ) - # Suppress the PP scheduler's direct ``grad_sync_func`` call (which - # bypasses ``no_sync``). Save the existing value so we can restore - # at finish/abort. PP=1's ``forward_backward_no_pipelining`` doesn't - # invoke this; nulling it is a no-op there. - # Read "config" via getattr-by-string so the token stays out of - # begin_train_step.__code__.co_names; otherwise cloudpickle matches - # torch.distributed.config (a non-pickleable ConfigModuleInstance). + # Null both mcore hooks that would fire a mid-step DP reduce: + # grad_sync_func — PP scheduler's direct call on last-MB boundaries. + # no_sync_func — forward_backward_no_pipelining wraps inner MBs + # in it and runs the LAST MB OUTSIDE, leaking + # per_param_grad_ready_counts past our outer + # no_sync. Override to nullcontext so only the + # outer no_sync in train_microbatch governs + # is_last_microbatch. + # getattr-by-string keeps "config" out of __code__.co_names so + # cloudpickle doesn't grab torch.distributed.config. model_config = getattr(self.model, "config", None) if model_config is not None: state["saved_grad_sync_func"] = getattr( model_config, "grad_sync_func", None ) + state["saved_no_sync_func"] = getattr(model_config, "no_sync_func", None) model_config.grad_sync_func = None + model_config.no_sync_func = nullcontext else: state["saved_grad_sync_func"] = None + state["saved_no_sync_func"] = None self._train_step_state = state @@ -1123,11 +1130,12 @@ def finish_train_step(self, step_id: str) -> dict[str, Any]: if self.cfg["megatron_cfg"]["empty_unused_memory_level"] >= 2: torch.cuda.empty_cache() - # Restore grad_sync_func before scheduler.step / further state. + # Restore the mcore hooks we nulled in begin_train_step. # See begin_train_step for why .config is accessed by string. finish_model_config = getattr(self.model, "config", None) if finish_model_config is not None: finish_model_config.grad_sync_func = state["saved_grad_sync_func"] + finish_model_config.no_sync_func = state["saved_no_sync_func"] # Scheduler increment matches sync path's ``increment=gbs``. self.scheduler.step(increment=state["gbs"]) @@ -1202,12 +1210,13 @@ def abort_train_step(self, step_id: str) -> None: f"abort_train_step({step_id!r}) does not match open step " f"{state['step_id']!r}" ) - # Restore grad_sync_func first so the model is back to a normal - # state before zero_grad_buffer touches anything. + # Restore the mcore hooks we nulled in begin_train_step before + # zero_grad_buffer touches anything. # See begin_train_step for why .config is accessed by string. abort_model_config = getattr(self.model, "config", None) if abort_model_config is not None: abort_model_config.grad_sync_func = state["saved_grad_sync_func"] + abort_model_config.no_sync_func = state["saved_no_sync_func"] self.model.zero_grad_buffer() self.optimizer.zero_grad() self._train_step_state = None diff --git a/tests/functional/L1_Functional_Tests_GRPO_3.sh b/tests/functional/L1_Functional_Tests_GRPO_3.sh index cb858eb4387..004194b4b6a 100644 --- a/tests/functional/L1_Functional_Tests_GRPO_3.sh +++ b/tests/functional/L1_Functional_Tests_GRPO_3.sh @@ -37,6 +37,7 @@ run_test() { run_test uv run --no-sync bash ./tests/functional/grpo_rm_env.sh run_test fast uv run --no-sync bash ./tests/functional/grpo_topp_topk.sh run_test uv run --no-sync bash ./tests/functional/vlm_grpo.sh +run_test fast uv run --no-sync bash ./tests/functional/grpo_dp_single_controller.sh cd ${PROJECT_ROOT}/tests if compgen -G ".coverage*" > /dev/null; then diff --git a/tests/functional/grpo_dp_single_controller.sh b/tests/functional/grpo_dp_single_controller.sh new file mode 100755 index 00000000000..9be3e844f8c --- /dev/null +++ b/tests/functional/grpo_dp_single_controller.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Lightweight e2e for examples/run_grpo_single_controller.py — exercises +# setup_handle + setup_single_controller_component + SingleControllerActor +# end-to-end. Same shape as tests/functional/grpo_dp_simple.sh (Qwen3-0.6B, +# 2 GPUs, a handful of steps); data_plane.enabled=true is mandatory for SC. + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +PROJECT_ROOT=$(realpath $SCRIPT_DIR/../..) +# Mark the current repo as safe, since wandb fetches metadata about the repo +git config --global --add safe.directory $PROJECT_ROOT + +set -eou pipefail + +EXP_NAME=$(basename $0 .sh) +EXP_DIR=$SCRIPT_DIR/$EXP_NAME +LOG_DIR=$EXP_DIR/logs +RUN_LOG=$EXP_DIR/run.log +export PYTHONPATH=${PROJECT_ROOT}:${PYTHONPATH:-} + +rm -rf $EXP_DIR $LOG_DIR +mkdir -p $EXP_DIR $LOG_DIR + +cd $PROJECT_ROOT +uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJECT_ROOT/nemo_rl \ + $PROJECT_ROOT/examples/run_grpo_single_controller.py \ + policy.model_name=Qwen/Qwen3-0.6B \ + grpo.num_prompts_per_step=2 \ + grpo.num_generations_per_prompt=4 \ + policy.train_global_batch_size=4 \ + policy.train_micro_batch_size=1 \ + cluster.gpus_per_node=2 \ + grpo.max_num_steps=2 \ + logger.tensorboard_enabled=true \ + logger.log_dir=$LOG_DIR \ + logger.wandb_enabled=false \ + logger.monitor_gpus=false \ + checkpointing.enabled=false \ + data_plane.enabled=true \ + data_plane.impl=transfer_queue \ + data_plane.backend=simple \ + staleness.min_prompt_groups_per_batch=2 \ + staleness.target_prompt_groups_per_step=2 \ + staleness.batch_selection_strategy=strict_on_policy \ + staleness.generations_per_prompt=4 \ + concurrency.max_inflight_prompts=4 \ + concurrency.max_buffered_rollouts=4 \ + training.max_train_steps=2 \ + $@ \ + 2>&1 | tee $RUN_LOG + +# TODO: add metrics diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index de0ab46126a..87eaed58bcf 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -28,11 +28,15 @@ import torch from tensordict import TensorDict -from nemo_rl.algorithms.single_controller import ( - SingleControllerActor, - SingleControllerConfig, +from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer +from nemo_rl.algorithms.single_controller import SingleControllerActor +from nemo_rl.algorithms.single_controller_utils import ( + AsyncRLConfig, + MasterConfig, + SingleControllerBundle, ) from nemo_rl.data_plane.adapters.noop import NoOpDataPlaneClient +from nemo_rl.experience.rollout_manager import RolloutManager # Reuse fixtures from the experience tests; same shape as test_async_rollout_manager. from tests.unit.experience.test_rollouts import ( @@ -174,34 +178,56 @@ def test_rollout_pump_writes_expected_tq_data( ) dp_adapter = _SyncDPAdapter(tq_actor) - cfg = SingleControllerConfig( - max_train_steps=1, - min_prompt_groups_per_batch=1, - generations_per_prompt=num_generations, - max_buffered_rollouts=max_rollout_prompts, - max_inflight_prompts=max_rollout_prompts, - max_weight_staleness_versions=0, - advantage_enabled=False, - diagnostics=False, - partition_id=_PARTITION_ID, - rollout_max_seq_len=max_seq_len, - rollout_max_turns=max_rollout_turns, - use_nemo_gym=False, + mc = MasterConfig.model_construct( + grpo={ + "max_num_steps": 1, + "max_num_epochs": None, + "num_generations_per_prompt": num_generations, + }, + async_rl=AsyncRLConfig( + max_weight_staleness_versions=0, + min_prompt_groups_per_batch=1, + target_prompt_groups_per_step=None, + batch_selection_strategy="strict_on_policy", + max_inflight_prompts=max_rollout_prompts, + max_buffered_rollouts=max_rollout_prompts, + ), ) # SingleControllerActor expects a StatefulDataLoader, but the pump only # iterates it (`for prompt in self._dataloader`), so any iterable works. dataloader = [input_sample] * max_rollout_prompts - ctrl = SingleControllerActor.remote( - cfg=cfg, - dp_client=dp_adapter, + tq_buffer = TQReplayBuffer( + dp_adapter, + partition_id=mc.partition_id, + pad_value_dict={"token_ids": int(tokenizer.pad_token_id or 0)}, + ) + rollout_manager = RolloutManager( + tokenizer=tokenizer, + env_handles=env_handles, + num_generations_per_prompt=num_generations, + max_seq_len=max_seq_len, + max_rollout_turns=max_rollout_turns, + policy_generation=vllm_generation, + use_nemo_gym=False, + tq_buffer=tq_buffer, + ) + bundle = SingleControllerBundle( gen_handle=vllm_generation, trainer_handle=object(), env_handles=env_handles, + train_cluster=None, + inference_cluster=None, + dp_client=dp_adapter, dataloader=dataloader, weight_synchronizer=object(), - tokenizer=tokenizer, + advantage_estimator=None, + loss_fn=None, + rollout_manager=rollout_manager, + tq_buffer=tq_buffer, + partition_id=_PARTITION_ID, ) + ctrl = SingleControllerActor.remote(master_config=mc, bundle=bundle) vllm_generation.prepare_for_generation() diff --git a/tests/unit/single_controller/test_single_controller_dryrun.py b/tests/unit/single_controller/test_single_controller_dryrun.py index 6ffbde56435..0a36c0abbe6 100644 --- a/tests/unit/single_controller/test_single_controller_dryrun.py +++ b/tests/unit/single_controller/test_single_controller_dryrun.py @@ -49,13 +49,51 @@ from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler -from nemo_rl.algorithms.single_controller import ( - SingleControllerActor, - SingleControllerConfig, +from nemo_rl.algorithms.single_controller import SingleControllerActor +from nemo_rl.algorithms.single_controller_utils import ( + AsyncRLConfig, + MasterConfig, + SingleControllerBundle, ) from nemo_rl.data_plane import KVBatchMeta from nemo_rl.experience.interfaces import Completion, PromptGroupRecord + +def _make_test_master_config( + *, + max_num_steps: int = 3, + max_num_epochs: int | None = None, + min_prompt_groups_per_batch: int = 1, + target_prompt_groups_per_step: int | None = None, + num_generations_per_prompt: int = 1, + batch_selection_strategy: str = "staleness_window", + max_weight_staleness_versions: int = 1, + max_inflight_prompts: int = 4, + max_buffered_rollouts: int = 4, +) -> MasterConfig: + """Build a MasterConfig for tests with only grpo + async_rl filled. + + Cross-cutting components (policy/data/cluster/...) are required by pydantic but + unused when a hand-built SingleControllerBundle is injected, so we use + model_construct to skip validation. SC-specific knobs live on the top-level + async_rl section (an AsyncRLConfig BaseModel). + """ + grpo_subset = { + "max_num_steps": max_num_steps, + "max_num_epochs": max_num_epochs, + "num_generations_per_prompt": num_generations_per_prompt, + } + async_rl = AsyncRLConfig( + max_weight_staleness_versions=max_weight_staleness_versions, + min_prompt_groups_per_batch=min_prompt_groups_per_batch, + target_prompt_groups_per_step=target_prompt_groups_per_step, + batch_selection_strategy=batch_selection_strategy, + max_inflight_prompts=max_inflight_prompts, + max_buffered_rollouts=max_buffered_rollouts, + ) + return MasterConfig.model_construct(grpo=grpo_subset, async_rl=async_rl) + + # ── Fake in-memory DataPlane ────────────────────────────────────────────── @@ -524,19 +562,15 @@ def _make_controller( max_buffered_rollouts=4, max_inflight_prompts=4, max_weight_staleness_versions=1, - advantage_enabled=False, advantage_estimator=None, - diagnostics=False, ): - cfg = SingleControllerConfig( - max_train_steps=max_train_steps, + mc = _make_test_master_config( + max_num_steps=max_train_steps, min_prompt_groups_per_batch=min_prompt_groups_per_batch, - generations_per_prompt=generations_per_prompt, + num_generations_per_prompt=generations_per_prompt, max_buffered_rollouts=max_buffered_rollouts, max_inflight_prompts=max_inflight_prompts, max_weight_staleness_versions=max_weight_staleness_versions, - advantage_enabled=advantage_enabled, - diagnostics=diagnostics, ) # SC expects a StatefulDataLoader, but the pump only iterates it @@ -545,25 +579,29 @@ def _make_controller( tq_buffer = TQReplayBuffer( dp_client, - partition_id=cfg.partition_id, + partition_id="rollout_data", pad_value_dict={"token_ids": 0}, ) rollout_manager = DryRunRolloutManager(gen, tq_buffer) if weight_sync is None: weight_sync = DryRunWeightSynchronizer() - return SingleControllerActor.remote( - cfg=cfg, - dp_client=dp_client, + bundle = SingleControllerBundle( gen_handle=gen, - env_handles={}, trainer_handle=trainer, + env_handles={}, + train_cluster=None, + inference_cluster=None, + dp_client=dp_client, dataloader=dataloader, weight_synchronizer=weight_sync, advantage_estimator=advantage_estimator, + loss_fn=None, rollout_manager=rollout_manager, tq_buffer=tq_buffer, + partition_id="rollout_data", ) + return SingleControllerActor.remote(master_config=mc, bundle=bundle) def test_dry_run_completes(self, ray_init): """SC completes N train steps without deadlock on CPU.""" @@ -601,7 +639,6 @@ def test_advantage_pump_writes_advantages_before_train(self, ray_init): max_train_steps=1, min_prompt_groups_per_batch=2, generations_per_prompt=1, - advantage_enabled=True, advantage_estimator=DryRunAdvantageEstimator(), ) @@ -811,68 +848,6 @@ def test_strict_on_policy_batch_sampler_evicts_old_groups(self): assert [m.sample_ids[0] for m in buf.meta_list] == ["g1_g0"] -@ray.remote(num_cpus=0) -class _ReapInFlightHelperActor: - """Tiny Ray actor exposing SingleControllerActor._reap_in_flight_nonblocking.""" - - async def reap(self, refs): - if not refs: - return [] - ref_to_task = {ref: asyncio.ensure_future(ref) for ref in refs} - await asyncio.wait(ref_to_task.values(), timeout=0.05) - pending = [] - for ref, task in ref_to_task.items(): - if task.done(): - task.result() - else: - task.cancel() - pending.append(ref) - return pending - - -@ray.remote -def _sleep_then_return(seconds: float, value: int = 0) -> int: - time.sleep(seconds) - return value - - -@ray.remote -def _raise_after(seconds: float) -> None: - time.sleep(seconds) - raise RuntimeError("boom") - - -class TestReapInFlightNonblocking: - """Validate _reap_in_flight_nonblocking helper semantics.""" - - def test_reap_empty_list_returns_empty(self, ray_init): - helper = _ReapInFlightHelperActor.remote() - result = ray.get(helper.reap.remote([])) - assert result == [] - - def test_reap_drains_completed_and_returns_pending(self, ray_init): - helper = _ReapInFlightHelperActor.remote() - # One finishes immediately, two stay pending - done_ref = _sleep_then_return.remote(0.0, 1) - pending1 = _sleep_then_return.remote(10.0, 2) - pending2 = _sleep_then_return.remote(10.0, 3) - # Give Ray a moment to mark done_ref as ready - time.sleep(0.5) - result = ray.get(helper.reap.remote([done_ref, pending1, pending2])) - # Only the still-pending refs are returned - assert len(result) == 2 - result_set = {r.hex() for r in result} - assert pending1.hex() in result_set - assert pending2.hex() in result_set - - def test_reap_surfaces_exception_from_completed(self, ray_init): - helper = _ReapInFlightHelperActor.remote() - bad_ref = _raise_after.remote(0.0) - time.sleep(0.5) - with pytest.raises(Exception): - ray.get(helper.reap.remote([bad_ref])) - - class TestDryRunTrainerSplitAPI: """Smoke test for DryRunTrainer split-API methods.""" @@ -931,11 +906,11 @@ def _make_controller( batch_selection_strategy="staleness_window", max_num_epochs=1, ): - cfg = SingleControllerConfig( - max_train_steps=max_train_steps, + mc = _make_test_master_config( + max_num_steps=max_train_steps, min_prompt_groups_per_batch=min_prompt_groups_per_batch, target_prompt_groups_per_step=target_prompt_groups_per_step, - generations_per_prompt=generations_per_prompt, + num_generations_per_prompt=generations_per_prompt, max_buffered_rollouts=max_buffered_rollouts, max_inflight_prompts=max_inflight_prompts, max_weight_staleness_versions=max_weight_staleness_versions, @@ -952,23 +927,27 @@ def _make_controller( tq_buffer = TQReplayBuffer( dp_client, - partition_id=cfg.partition_id, + partition_id="rollout_data", pad_value_dict={"token_ids": 0}, ) rollout_manager = DryRunRolloutManager(gen, tq_buffer) - return SingleControllerActor.remote( - cfg=cfg, - dp_client=dp_client, + bundle = SingleControllerBundle( gen_handle=gen, - env_handles={}, trainer_handle=trainer, + env_handles={}, + train_cluster=None, + inference_cluster=None, + dp_client=dp_client, dataloader=dataloader, weight_synchronizer=weight_sync, + advantage_estimator=None, + loss_fn=None, rollout_manager=rollout_manager, tq_buffer=tq_buffer, - advantage_estimator=None, + partition_id="rollout_data", ) + return SingleControllerActor.remote(master_config=mc, bundle=bundle) def test_streaming_dispatches_in_arrival_order(self, ray_init): """SC dispatches train_microbatch in order groups commit at DP.""" diff --git a/tests/unit/single_controller/test_single_controller_setup.py b/tests/unit/single_controller/test_single_controller_setup.py new file mode 100644 index 00000000000..7dd8277962d --- /dev/null +++ b/tests/unit/single_controller/test_single_controller_setup.py @@ -0,0 +1,260 @@ +"""Unit tests for nemo_rl.algorithms.single_controller_utils.setup. + +setup is heavy (it spins up Ray clusters, TQPolicy, generation backend, ...) so it's +exercised through monkey-patching rather than as a real e2e — the unit tests cover the +shape of the contract, not the underlying initialization. The full path is covered by +the functional test at tests/functional/grpo_dp_single_controller.sh. +""" + +from __future__ import annotations + +from unittest.mock import MagicMock, patch + +import pytest + +from nemo_rl.algorithms.single_controller_utils import ( + MasterConfig, + SingleControllerBundle, + setup, +) +from nemo_rl.algorithms.single_controller_utils import setup as setup_module + + +def _make_master_config( + *, + dp_enabled: bool = True, + use_multiple_dataloader: bool = False, + colocated: bool = True, + backend: str = "vllm", + megatron_enabled: bool = False, + env: dict | None = None, + max_num_steps: int = 100, + max_num_epochs: int = 1, + num_prompts_per_step: int = 4, +) -> MasterConfig: + """Build a partially-populated MasterConfig for unit tests. + + Cross-cutting components (cluster/checkpointing/...) are required by pydantic for + normal load but unused here — model_construct skips validation, and we hand-fill + only the dict-shaped fields setup reads. + """ + return MasterConfig.model_construct( + data_plane={"enabled": dp_enabled, "impl": "transfer_queue"}, + data={ + "use_multiple_dataloader": use_multiple_dataloader, + "shuffle": False, + "num_workers": 0, + "train": [{"env_name": "math"}], + }, + grpo={ + "max_num_steps": max_num_steps, + "max_num_epochs": max_num_epochs, + "num_prompts_per_step": num_prompts_per_step, + "num_generations_per_prompt": 2, + "max_rollout_turns": 1, + }, + policy={ + "max_total_sequence_length": 32, + "megatron_cfg": {"enabled": megatron_enabled}, + "generation": { + "backend": backend, + "colocated": {"enabled": colocated, "resources": {}}, + }, + }, + env=env if env is not None else {}, + ) + + +@pytest.fixture +def patched_factories(): + """Patch every external factory setup calls. + + Returns a dict of mocks keyed by name so individual tests can assert on call args + without re-importing the patch handles. + """ + fake_dataset = list(range(8)) + fake_dataloader = MagicMock(name="dataloader") + # len(dataloader) used by the Megatron train_iters injection. + fake_dataloader.__len__ = MagicMock(return_value=4) + fake_env_handles = {"math": MagicMock(name="math_env")} + + with ( + patch.object( + setup_module, + "setup_response_data", + return_value=(fake_dataset, None, fake_env_handles, {}), + ) as mock_setup_response, + patch.object( + setup_module, + "StatefulDataLoader", + return_value=fake_dataloader, + ) as mock_dataloader, + patch.object( + setup_module, + "_build_clusters", + return_value=( + MagicMock(name="train_cluster"), + MagicMock(name="inference_cluster"), + ), + ) as mock_clusters, + patch.object( + setup_module, "_build_generation", return_value=MagicMock(name="gen") + ) as mock_gen, + patch.object( + setup_module, "_build_trainer", return_value=MagicMock(name="policy") + ) as mock_trainer, + patch.object( + setup_module, + "build_data_plane_client", + return_value=MagicMock(name="dp_client"), + ) as mock_dp_client, + patch.object( + setup_module, + "create_weight_synchronizer", + return_value=MagicMock(name="weight_sync"), + ) as mock_weight_sync, + patch.object( + setup_module, + "_create_advantage_estimator", + return_value=MagicMock(name="adv"), + ) as mock_adv, + patch.object( + setup_module, "ClippedPGLossFn", return_value=MagicMock(name="loss_fn") + ) as mock_loss, + patch.object( + setup_module, + "_generation_max_seq_len", + return_value=32, + ), + ): + yield { + "setup_response_data": mock_setup_response, + "StatefulDataLoader": mock_dataloader, + "_build_clusters": mock_clusters, + "_build_generation": mock_gen, + "_build_trainer": mock_trainer, + "build_data_plane_client": mock_dp_client, + "create_weight_synchronizer": mock_weight_sync, + "_create_advantage_estimator": mock_adv, + "ClippedPGLossFn": mock_loss, + "dataloader": fake_dataloader, + "env_handles": fake_env_handles, + } + + +class TestSetup: + """setup arg validation + bundle assembly.""" + + def test_raises_when_data_plane_disabled(self): + mc = _make_master_config(dp_enabled=False) + with pytest.raises(ValueError, match="data_plane.enabled=True"): + setup(mc, MagicMock()) + + def test_multiple_dataloader_not_supported(self): + mc = _make_master_config(use_multiple_dataloader=True) + with pytest.raises(NotImplementedError, match="use_multiple_dataloader"): + setup(mc, MagicMock(pad_token_id=0)) + + def test_returns_bundle(self, patched_factories): + mc = _make_master_config(colocated=True) + tokenizer = MagicMock(pad_token_id=0) + + bundle = setup(mc, tokenizer) + + assert isinstance(bundle, SingleControllerBundle) + assert bundle.gen_handle is patched_factories["_build_generation"].return_value + assert bundle.trainer_handle is patched_factories["_build_trainer"].return_value + assert bundle.env_handles is patched_factories["env_handles"] + assert ( + bundle.dp_client + is patched_factories["build_data_plane_client"].return_value + ) + assert bundle.dataloader is patched_factories["dataloader"] + assert bundle.weight_synchronizer is ( + patched_factories["create_weight_synchronizer"].return_value + ) + assert bundle.advantage_estimator is ( + patched_factories["_create_advantage_estimator"].return_value + ) + assert bundle.loss_fn is patched_factories["ClippedPGLossFn"].return_value + # tq_buffer + rollout_manager are constructed inline (not mocked). + assert bundle.tq_buffer is not None + assert bundle.rollout_manager is not None + # rollout_manager binds the same tq_buffer for the writer + sampler. + assert bundle.rollout_manager._tq_buffer is bundle.tq_buffer + # tq_buffer wires the dp_client + default partition. + assert bundle.tq_buffer._dp_client is bundle.dp_client + assert bundle.partition_id == "rollout_data" + assert bundle.tq_buffer._partition_id == "rollout_data" + + def test_env_handles_sourced_from_setup_response_data(self, patched_factories): + """setup_response_data receives master_config.env and supplies env handles.""" + math_env_cfg = {"some": "value"} + mc = _make_master_config(env={"math": math_env_cfg}) + + bundle = setup(mc, MagicMock(pad_token_id=0)) + + _, call_kwargs = patched_factories["setup_response_data"].call_args + assert call_kwargs["env_configs"] == {"math": math_env_cfg} + assert bundle.env_handles is patched_factories["env_handles"] + + def test_weight_sync_factory_args(self, patched_factories): + """create_weight_synchronizer receives policy / generation / topology.""" + mc = _make_master_config(colocated=False, backend="vllm") + tokenizer = MagicMock(pad_token_id=0) + + setup(mc, tokenizer) + + _, factory_kwargs = patched_factories["create_weight_synchronizer"].call_args + assert ( + factory_kwargs["policy"] is patched_factories["_build_trainer"].return_value + ) + assert ( + factory_kwargs["generation"] + is patched_factories["_build_generation"].return_value + ) + assert factory_kwargs["generation_backend"] == "vllm" + assert factory_kwargs["colocated"] is False + + def test_custom_partition_id(self, patched_factories): + mc = _make_master_config() + tokenizer = MagicMock(pad_token_id=7) + + bundle = setup(mc, tokenizer, partition_id="custom_partition") + + assert bundle.partition_id == "custom_partition" + assert bundle.tq_buffer._partition_id == "custom_partition" + assert bundle.tq_buffer._pad_value_dict == { + "token_ids": 7, + "input_ids": 7, + } + + def test_megatron_train_iters_capped_by_max_num_steps(self, patched_factories): + """train_iters = min(max_num_steps, max_num_epochs * len(dataloader)).""" + mc = _make_master_config( + megatron_enabled=True, + max_num_steps=2, + max_num_epochs=1, + ) + # patched dataloader has len() == 4, so the min picks max_num_steps. + setup(mc, MagicMock(pad_token_id=0)) + + assert mc.policy["megatron_cfg"]["train_iters"] == 2 + + def test_megatron_train_iters_capped_by_dataloader_epochs(self, patched_factories): + """train_iters drops to max_num_epochs * len(dataloader) when smaller.""" + mc = _make_master_config( + megatron_enabled=True, + max_num_steps=1000, + max_num_epochs=2, + ) + # patched dataloader has len() == 4 → 2 * 4 = 8 < 1000. + setup(mc, MagicMock(pad_token_id=0)) + + assert mc.policy["megatron_cfg"]["train_iters"] == 8 + + def test_megatron_train_iters_not_set_when_disabled(self, patched_factories): + mc = _make_master_config(megatron_enabled=False) + setup(mc, MagicMock(pad_token_id=0)) + + assert "train_iters" not in mc.policy.get("megatron_cfg", {}) From 41f88f0c96e222417ae0f33ab2f8a7fa48fdb7ae Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Mon, 15 Jun 2026 01:04:03 -0700 Subject: [PATCH 06/44] refactor(single-controller): rename setup entrypoint; drop dryrun test Signed-off-by: Yuki Huang --- examples/run_grpo_single_controller.py | 9 +- nemo_rl/algorithms/single_controller.py | 2 +- .../single_controller_utils/__init__.py | 4 +- .../single_controller_utils/setup.py | 4 +- nemo_rl/experience/rollout_manager.py | 2 +- .../single_controller/test_rollout_pump.py | 9 +- .../test_single_controller_dryrun.py | 1272 ----------------- .../test_single_controller_setup.py | 55 +- .../test_tq_replay_buffer.py | 24 - 9 files changed, 46 insertions(+), 1335 deletions(-) delete mode 100644 tests/unit/single_controller/test_single_controller_dryrun.py diff --git a/examples/run_grpo_single_controller.py b/examples/run_grpo_single_controller.py index b1c22ee5bfa..7fa3a854321 100644 --- a/examples/run_grpo_single_controller.py +++ b/examples/run_grpo_single_controller.py @@ -14,7 +14,7 @@ """Async GRPO launcher driven by the SingleController actor. -Builds the full SC bundle driver-side via single_controller_utils.setup and hands it +Builds the full SC bundle driver-side via setup_single_controller and hands it to SingleControllerActor. Mirrors run_grpo.py for config loading so the same YAML files apply. data_plane.enabled=true is mandatory. """ @@ -27,7 +27,10 @@ from omegaconf import OmegaConf from nemo_rl.algorithms.single_controller import SingleControllerActor -from nemo_rl.algorithms.single_controller_utils import MasterConfig, setup +from nemo_rl.algorithms.single_controller_utils import ( + MasterConfig, + setup_single_controller, +) from nemo_rl.algorithms.utils import get_tokenizer from nemo_rl.distributed.virtual_cluster import init_ray from nemo_rl.models.generation import configure_generation_config @@ -104,7 +107,7 @@ def main() -> None: has_refit_draft_weights=has_refit_draft_weights, ) - bundle = setup(config, tokenizer) + bundle = setup_single_controller(config, tokenizer) print("🚀 Launching SingleControllerActor") sc = SingleControllerActor.remote(master_config=config, bundle=bundle) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index afc7b9bb50d..4472afe4b9c 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -73,7 +73,7 @@ def __init__( Args: master_config: SC MasterConfig. - bundle: Pre-built bundle from single_controller_utils.setup. Tests can + bundle: Pre-built bundle from setup_single_controller. Tests can construct a bundle by hand (or with fakes) to bypass the real factories. """ self._advantage_cfg = AdvantageConfig() diff --git a/nemo_rl/algorithms/single_controller_utils/__init__.py b/nemo_rl/algorithms/single_controller_utils/__init__.py index 9c16687db7f..a2c7001f926 100644 --- a/nemo_rl/algorithms/single_controller_utils/__init__.py +++ b/nemo_rl/algorithms/single_controller_utils/__init__.py @@ -22,7 +22,7 @@ ) from nemo_rl.algorithms.single_controller_utils.setup import ( SingleControllerBundle, - setup, + setup_single_controller, ) __all__ = [ @@ -31,5 +31,5 @@ "MasterConfig", "SingleControllerBundle", "WeightSyncConfig", - "setup", + "setup_single_controller", ] diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index c043c1154bf..b222148ce61 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -48,7 +48,7 @@ @dataclass class SingleControllerBundle: - """All inputs SingleControllerActor needs, built driver-side by setup(). + """All inputs SingleControllerActor needs, built driver-side by setup_single_controller(). Passed as a single arg to SingleControllerActor.remote so the actor's __init__ does no construction work — every heavy object is cloudpickled in. @@ -225,7 +225,7 @@ def _maybe_inject_megatron_train_iters( ) -def setup( +def setup_single_controller( master_config: MasterConfig, tokenizer: PreTrainedTokenizerBase, *, diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index c2d6bd658ef..56dfcd9dd24 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -585,7 +585,7 @@ def _compute_rollout_metrics( # 1. Turn RolloutManager into a Ray actor. # 2. Keep policy_generation driver-constructed and pass it in (don't # build it inside the rollout actor — avoids nested Ray actors). -# 3. Construct the rollout actor in single_controller_utils.setup and +# 3. Construct the rollout actor in setup_single_controller and # drop the inline RolloutManager construction there. class RolloutManager: """Routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym), and pushes results to a TQReplayBuffer.""" diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index 87eaed58bcf..ff98698daf8 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -36,6 +36,7 @@ SingleControllerBundle, ) from nemo_rl.data_plane.adapters.noop import NoOpDataPlaneClient +from nemo_rl.distributed.batched_data_dict import BatchedDataDict from nemo_rl.experience.rollout_manager import RolloutManager # Reuse fixtures from the experience tests; same shape as test_async_rollout_manager. @@ -193,13 +194,13 @@ def test_rollout_pump_writes_expected_tq_data( max_buffered_rollouts=max_rollout_prompts, ), ) - # SingleControllerActor expects a StatefulDataLoader, but the pump only - # iterates it (`for prompt in self._dataloader`), so any iterable works. - dataloader = [input_sample] * max_rollout_prompts + # Wrap each value in a single-element list so size==1 and v[0] returns the original field. + batched_sample = BatchedDataDict({k: [v] for k, v in input_sample.items()}) + dataloader = [batched_sample] * max_rollout_prompts tq_buffer = TQReplayBuffer( dp_adapter, - partition_id=mc.partition_id, + partition_id=_PARTITION_ID, pad_value_dict={"token_ids": int(tokenizer.pad_token_id or 0)}, ) rollout_manager = RolloutManager( diff --git a/tests/unit/single_controller/test_single_controller_dryrun.py b/tests/unit/single_controller/test_single_controller_dryrun.py deleted file mode 100644 index 0a36c0abbe6..00000000000 --- a/tests/unit/single_controller/test_single_controller_dryrun.py +++ /dev/null @@ -1,1272 +0,0 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. -# -# 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. - -"""Dry-run tests for SingleController asyncio skeleton (C-03). - -Validates the three-pump asyncio architecture using stub actors with -configurable sleep latencies — no GPU, no real model weights required. - -Key questions answered: - - Do all 3 pumps run concurrently? (rollout_pump dispatches while - train_pump is "busy") - - Does buffer capacity correctly block rollout_pump when capacity is full? - - Does _rollout_permitted correctly pause dispatch during _sync_weights? - - RISK-06: does a blocking policy.train() call freeze the event loop? - (train_from_meta uses asyncio.sleep to simulate, so this is non-blocking - by construction in the dry-run — see dedicated RISK-06 test below) -""" - -from __future__ import annotations - -import asyncio -import os -import threading -import time -from typing import Any - -import pytest -import ray -import torch -from tensordict import TensorDict - -# ── Ray temp dir: must be SHORT on macOS (AF_UNIX path limit = 103 bytes) ─ -# Use a fixed short path under /tmp to avoid hitting the socket length limit. -_RAY_TEMP = "/tmp/nrl_sc_test" -os.makedirs(_RAY_TEMP, exist_ok=True) -os.environ["RAY_TEMP_DIR"] = _RAY_TEMP -os.environ["RAY_TMPDIR"] = _RAY_TEMP - -from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer -from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler -from nemo_rl.algorithms.single_controller import SingleControllerActor -from nemo_rl.algorithms.single_controller_utils import ( - AsyncRLConfig, - MasterConfig, - SingleControllerBundle, -) -from nemo_rl.data_plane import KVBatchMeta -from nemo_rl.experience.interfaces import Completion, PromptGroupRecord - - -def _make_test_master_config( - *, - max_num_steps: int = 3, - max_num_epochs: int | None = None, - min_prompt_groups_per_batch: int = 1, - target_prompt_groups_per_step: int | None = None, - num_generations_per_prompt: int = 1, - batch_selection_strategy: str = "staleness_window", - max_weight_staleness_versions: int = 1, - max_inflight_prompts: int = 4, - max_buffered_rollouts: int = 4, -) -> MasterConfig: - """Build a MasterConfig for tests with only grpo + async_rl filled. - - Cross-cutting components (policy/data/cluster/...) are required by pydantic but - unused when a hand-built SingleControllerBundle is injected, so we use - model_construct to skip validation. SC-specific knobs live on the top-level - async_rl section (an AsyncRLConfig BaseModel). - """ - grpo_subset = { - "max_num_steps": max_num_steps, - "max_num_epochs": max_num_epochs, - "num_generations_per_prompt": num_generations_per_prompt, - } - async_rl = AsyncRLConfig( - max_weight_staleness_versions=max_weight_staleness_versions, - min_prompt_groups_per_batch=min_prompt_groups_per_batch, - target_prompt_groups_per_step=target_prompt_groups_per_step, - batch_selection_strategy=batch_selection_strategy, - max_inflight_prompts=max_inflight_prompts, - max_buffered_rollouts=max_buffered_rollouts, - ) - return MasterConfig.model_construct(grpo=grpo_subset, async_rl=async_rl) - - -# ── Fake in-memory DataPlane ────────────────────────────────────────────── - - -@ray.remote(num_cpus=0) -class FakeDataPlaneActor: - """Minimal in-memory DataPlane actor for dry-run testing. - - Stores rows by sample_id and exposes the current DataPlane methods - SingleController uses: get_samples, and clear_samples. - Not production code — used only for C-03 dry-run validation. - """ - - def __init__(self, partition_id: str = "rollout_data"): - self._partition_id = partition_id - self._rows: dict[str, dict] = {} - self._consumed: dict[str, set[str]] = {} - self._lock = threading.Lock() - self._clear_calls: list[list[str]] = [] - - def put_samples( - self, - sample_ids: list[str], - partition_id: str, - fields: TensorDict | None = None, - tags: list[dict[str, Any]] | None = None, - ) -> KVBatchMeta: - assert partition_id == self._partition_id - with self._lock: - for i, sample_id in enumerate(sample_ids): - row_fields = set(fields.keys()) if fields is not None else set() - row = self._rows.setdefault( - sample_id, - { - "fields": set(), - "values": {}, - "tag": dict(tags[i]) if tags is not None else {}, - }, - ) - row["fields"].update(row_fields) - if tags is not None: - row["tag"] = dict(tags[i]) - if fields is not None: - for field_name in fields.keys(): - value = fields[field_name] - assert isinstance(value, torch.Tensor) - row["values"][field_name] = value[i].detach().clone() - return KVBatchMeta( - partition_id=partition_id, - task_name=None, - sample_ids=list(sample_ids), - fields=list(fields.keys()) if fields is not None else None, - tags=[dict(t) for t in tags] if tags is not None else None, - ) - - def get_samples( - self, - sample_ids: list[str], - partition_id: str, - select_fields: list[str], - ) -> TensorDict: - assert partition_id == self._partition_id - values: dict[str, torch.Tensor] = {} - with self._lock: - for field_name in select_fields: - rows = [] - for sample_id in sample_ids: - rows.append(self._rows[sample_id]["values"][field_name]) - values[field_name] = torch.stack(rows, dim=0) - return TensorDict( - values, - batch_size=[len(sample_ids)], - ) - - def clear_samples(self, sample_ids: list[str] | None, partition_id: str) -> None: - assert partition_id == self._partition_id - with self._lock: - ids = list(self._rows) if sample_ids is None else sample_ids - self._clear_calls.append(list(ids)) - for sample_id in ids: - self._rows.pop(sample_id, None) - for consumed in self._consumed.values(): - consumed.discard(sample_id) - - def get_clear_calls(self) -> list[list[str]]: - with self._lock: - return [list(c) for c in self._clear_calls] - - def depth(self) -> int: - with self._lock: - return len(self._rows) - - -# ── Dry-run stub actors ─────────────────────────────────────────────────── - - -@ray.remote(num_cpus=0) -class DryRunGenWorker: - """Stub GenerationWorkerActor. - - Returns a PromptGroupRecord whose prompt_idx and per-completion reward - carry the call_count so the dry-run record-converter stub can reproduce - the train_batch fields deterministically. - """ - - def __init__(self, gen_latency_s: float = 0.1): - self._gen_latency_s = gen_latency_s - self._call_count = 0 - self._call_timestamps: list[float] = [] - - async def generate(self, prompt: str) -> PromptGroupRecord: - self._call_count += 1 - self._call_timestamps.append(time.monotonic()) - await asyncio.sleep(self._gen_latency_s) - prompt_msg = { - "role": "user", - "token_ids": torch.tensor([self._call_count] * 3, dtype=torch.long), - } - assistant_msg = { - "role": "assistant", - "token_ids": torch.tensor([self._call_count] * 3, dtype=torch.long), - "generation_logprobs": torch.zeros(3, dtype=torch.float32), - } - return PromptGroupRecord( - prompt_idx=self._call_count, - prompt=[prompt_msg], - extra_env_info=None, - metadata={}, - completions=[ - Completion( - message_log=[prompt_msg, assistant_msg], - env_extras=None, - truncated=False, - reward=float(self._call_count), - ), - ], - rollout_metrics={}, - ) - - def get_call_count(self) -> int: - return self._call_count - - def get_call_timestamps(self) -> list[float]: - return list(self._call_timestamps) - - -@ray.remote(num_cpus=0) -class DryRunStaggeredGenWorker: - """Gen worker that reads latency and group label from the prompt. - - Prompt format: ``"{idx}:{latency}"``. Sleeps for ``latency`` then - returns a PromptGroupRecord tagged with ``group_id="group-{idx:04d}"``; - DryRunRolloutManager is responsible for pushing it to TQ. - """ - - def __init__(self) -> None: - self._call_timestamps: list[float] = [] - - async def generate(self, prompt: str) -> PromptGroupRecord: - idx_str, latency_str = prompt.split(":") - idx = int(idx_str) - latency = float(latency_str) - self._call_timestamps.append(time.monotonic()) - await asyncio.sleep(latency) - group_id = f"group-{idx:04d}" - prompt_msg = { - "role": "user", - "token_ids": torch.tensor([idx] * 3, dtype=torch.long), - } - assistant_msg = { - "role": "assistant", - "token_ids": torch.tensor([idx] * 3, dtype=torch.long), - "generation_logprobs": torch.zeros(3, dtype=torch.float32), - } - return PromptGroupRecord( - prompt_idx=idx, - prompt=[prompt_msg], - extra_env_info=None, - metadata={"group_id": group_id}, - completions=[ - Completion( - message_log=[prompt_msg, assistant_msg], - env_extras=None, - truncated=False, - reward=float(idx), - ), - ], - rollout_metrics={}, - ) - - def get_call_timestamps(self) -> list[float]: - return list(self._call_timestamps) - - -@ray.remote(num_cpus=0) -class DryRunTrainer: - """Stub PolicyTrainerActor. - - Implements the same interface as production trainer: - train_from_meta(meta) → fetches from its own dp_client, sleeps, returns result - - Production ``PolicyTrainerActor`` owns its dp_client (built from - ``dp_cfg`` at construction). This stub mirrors that by binding the - dp_client handle at ``__init__`` time, not per call. - - Uses asyncio.sleep so event loop stays responsive — other pumps continue. - """ - - def __init__( - self, - dp_client: Any, - train_latency_s: float = 0.2, - expect_advantages: bool = False, - microbatch_latency_s: float = 0.0, - ): - self._dp_client = dp_client - self._train_latency_s = train_latency_s - self._expect_advantages = expect_advantages - self._microbatch_latency_s = microbatch_latency_s - self._trainer_version = 0 - self._train_count = 0 - self._train_start_times: list[float] = [] - self._last_advantages: torch.Tensor | None = None - # Split API state - self._open_step_id: str | None = None - self._microbatch_calls: list[tuple[str, list[str], float]] = [] - self._finish_calls: list[str] = [] - self._abort_calls: list[str] = [] - - async def begin_train_step( - self, - step_id: str, - loss_fn: Any = None, - gbs: int = 0, - mbs: int = 0, - ) -> None: - del loss_fn, gbs, mbs - if self._open_step_id is not None: - raise RuntimeError( - f"begin_train_step called while step {self._open_step_id} is open" - ) - self._open_step_id = step_id - - async def train_microbatch_from_meta(self, step_id: str, meta: KVBatchMeta) -> None: - if self._open_step_id is None: - raise RuntimeError("train_microbatch_from_meta called with no open step") - if step_id != self._open_step_id: - raise RuntimeError( - f"train_microbatch_from_meta step_id={step_id!r} != open {self._open_step_id!r}" - ) - now = time.monotonic() - self._microbatch_calls.append((step_id, list(meta.sample_ids), now)) - self._train_start_times.append(now) - if self._expect_advantages: - data = await self._dp_client.get_samples.remote( - sample_ids=meta.sample_ids, - partition_id=meta.partition_id, - select_fields=["input_ids", "advantages"], - ) - advantages = data["advantages"].detach().clone() - if self._last_advantages is None: - self._last_advantages = advantages - else: - self._last_advantages = torch.cat( - [self._last_advantages, advantages], dim=0 - ) - if self._microbatch_latency_s > 0: - await asyncio.sleep(self._microbatch_latency_s) - - async def finish_train_step(self, step_id: str) -> dict: - if self._open_step_id is None: - raise RuntimeError("finish_train_step called with no open step") - if step_id != self._open_step_id: - raise RuntimeError( - f"finish_train_step step_id={step_id!r} != open {self._open_step_id!r}" - ) - self._finish_calls.append(step_id) - self._open_step_id = None - self._trainer_version += 1 - self._train_count += 1 - return { - "loss": 1.0 / (self._trainer_version + 1), - "trainer_version": self._trainer_version, - } - - async def abort_train_step(self, step_id: str) -> None: - self._abort_calls.append(step_id) - self._open_step_id = None - - async def prepare_logprobs_from_meta(self, meta: KVBatchMeta) -> None: - del meta - return None - - def get_open_step_id(self) -> str | None: - return self._open_step_id - - def get_microbatch_calls(self) -> list[tuple[str, list[str], float]]: - return list(self._microbatch_calls) - - def get_finish_calls(self) -> list[str]: - return list(self._finish_calls) - - def get_abort_calls(self) -> list[str]: - return list(self._abort_calls) - - async def train_from_meta(self, meta: KVBatchMeta) -> dict: - """Simulate a training step.""" - self._train_start_times.append(time.monotonic()) - # Fetch records from DataPlane via the trainer's own client — - # same as production TQPolicy.train_from_meta. - select_fields = ["input_ids"] - if self._expect_advantages: - select_fields.append("advantages") - data = await self._dp_client.get_samples.remote( - sample_ids=meta.sample_ids, - partition_id=meta.partition_id, - select_fields=select_fields, - ) - if self._expect_advantages: - self._last_advantages = data["advantages"].detach().clone() - await asyncio.sleep(self._train_latency_s) - self._trainer_version += 1 - self._train_count += 1 - return { - "loss": 1.0 / (self._trainer_version + 1), - "trainer_version": self._trainer_version, - "clear_samples": True, - } - - def get_trainer_version(self) -> int: - return self._trainer_version - - def get_train_count(self) -> int: - return self._train_count - - def get_train_start_times(self) -> list[float]: - return list(self._train_start_times) - - def get_last_advantages(self) -> torch.Tensor | None: - return self._last_advantages - - -class DryRunAdvantageEstimator: - """Small estimator used by the dry-run SC advantage stage test.""" - - def compute_advantage( - self, - prompt_ids, - rewards, - mask, - repeated_batch, - **kwargs, - ): - del prompt_ids, repeated_batch, kwargs - centered = rewards - rewards.mean() - return centered.unsqueeze(-1).expand(mask.shape) - - -class DryRunRolloutManager: - """Dry-run mock of ``RolloutManager`` for SC dry-run tests. - - Production ``RolloutManager`` is a plain (non-Ray) class living in the - SC actor's process and writes via ``TQReplayBuffer.add``; this mock - matches that shape. Generation is delegated to a ``DryRunGenWorker`` - Ray actor so the test can inspect call counts and timestamps from - outside the SC actor. - """ - - def __init__(self, gen_actor: Any, tq_buffer: TQReplayBuffer) -> None: - self._gen_actor = gen_actor - self._tq_buffer = tq_buffer - self._weight_version: int = 0 - - def set_weight_version(self, version: int) -> None: - self._weight_version = int(version) - - async def generate_and_push(self, prompt: str) -> None: - record = await self._gen_actor.generate.remote(prompt) - group_id = (record.metadata or {}).get("group_id") - await self._tq_buffer.add( - record, - weight_version=self._weight_version, - group_id=group_id, - ) - - -class DryRunWeightSynchronizer: - """Stub WeightSynchronizer — bumps the rollout manager's weight_version. - - In production this would call ``WeightSynchronizer.sync_weights()`` - which dispatches to IPC/HTTP/NCCL based on deployment config and SC - then mirrors ``trainer_version`` onto the rollout manager. - """ - - def __init__(self, sync_latency_s: float = 0.05): - self._sync_latency_s = sync_latency_s - self._sync_count = 0 - self._sync_timestamps: list[float] = [] - - async def sync_weights(self, trainer_version: int) -> None: - self._sync_count += 1 - self._sync_timestamps.append(time.monotonic()) - await asyncio.sleep(self._sync_latency_s) - - -# ── pytest fixtures ─────────────────────────────────────────────────────── - - -@pytest.fixture(scope="module") -def ray_init(): - if not ray.is_initialized(): - ray.init(ignore_reinit_error=True, num_cpus=4) - yield - # Don't shutdown — other tests in the module may need Ray - - -class _FakeBuffer: - """Mock of TQReplayBuffer exposing only the surface StalenessSampler reads.""" - - def __init__(self, partition_id: str = "rollout_data") -> None: - self._partition_id = partition_id - self.meta_list: list[KVBatchMeta] = [] - self.weight_list: list[int] = [] - - def add(self, group_id: str, weight: int, group_size: int = 1) -> None: - sample_ids = [f"{group_id}_g{i}" for i in range(group_size)] - self.meta_list.append( - KVBatchMeta( - partition_id=self._partition_id, - task_name=None, - sample_ids=sample_ids, - tags=[{"weight_version": weight, "group_id": group_id}] * group_size, - ) - ) - self.weight_list.append(weight) - - async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: - del remove_in_dp - for i in sorted(idxs, reverse=True): - del self.meta_list[i] - del self.weight_list[i] - return len(idxs) - - -def _buffer_with_versions(versions: list[int]) -> _FakeBuffer: - buf = _FakeBuffer() - for i, w in enumerate(versions): - buf.add(f"g{i}", weight=w) - return buf - - -# ── tests ───────────────────────────────────────────────────────────────── - - -class TestSingleControllerDryRun: - """Validate asyncio skeleton concurrency and backpressure.""" - - def _make_controller( - self, - dp_client, - gen, - trainer, - weight_sync=None, - max_train_steps=3, - min_prompt_groups_per_batch=1, - generations_per_prompt=1, - max_buffered_rollouts=4, - max_inflight_prompts=4, - max_weight_staleness_versions=1, - advantage_estimator=None, - ): - mc = _make_test_master_config( - max_num_steps=max_train_steps, - min_prompt_groups_per_batch=min_prompt_groups_per_batch, - num_generations_per_prompt=generations_per_prompt, - max_buffered_rollouts=max_buffered_rollouts, - max_inflight_prompts=max_inflight_prompts, - max_weight_staleness_versions=max_weight_staleness_versions, - ) - - # SC expects a StatefulDataLoader, but the pump only iterates it - # (`for prompt in self._dataloader`), so a list satisfies the contract. - dataloader = [f"prompt_{i}" for i in range(10)] - - tq_buffer = TQReplayBuffer( - dp_client, - partition_id="rollout_data", - pad_value_dict={"token_ids": 0}, - ) - rollout_manager = DryRunRolloutManager(gen, tq_buffer) - if weight_sync is None: - weight_sync = DryRunWeightSynchronizer() - - bundle = SingleControllerBundle( - gen_handle=gen, - trainer_handle=trainer, - env_handles={}, - train_cluster=None, - inference_cluster=None, - dp_client=dp_client, - dataloader=dataloader, - weight_synchronizer=weight_sync, - advantage_estimator=advantage_estimator, - loss_fn=None, - rollout_manager=rollout_manager, - tq_buffer=tq_buffer, - partition_id="rollout_data", - ) - return SingleControllerActor.remote(master_config=mc, bundle=bundle) - - def test_dry_run_completes(self, ray_init): - """SC completes N train steps without deadlock on CPU.""" - dp_client = FakeDataPlaneActor.remote() - gen = DryRunGenWorker.remote(gen_latency_s=0.05) - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.1) - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - max_train_steps=3, - min_prompt_groups_per_batch=1, - generations_per_prompt=1, - ) - - result = ray.get(ctrl.run.remote(), timeout=30) - assert result["train_steps"] == 3 - assert result["trainer_version"] == 3 - - def test_advantage_pump_writes_advantages_before_train(self, ray_init): - """SC computes advantages from DataPlane inputs and writes them back.""" - dp_client = FakeDataPlaneActor.remote() - gen = DryRunGenWorker.remote(gen_latency_s=0.01) - trainer = DryRunTrainer.remote( - dp_client, - train_latency_s=0.01, - expect_advantages=True, - ) - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - max_train_steps=1, - min_prompt_groups_per_batch=2, - generations_per_prompt=1, - advantage_estimator=DryRunAdvantageEstimator(), - ) - - result = ray.get(ctrl.run.remote(), timeout=30) - assert result["train_steps"] == 1 - - advantages = ray.get(trainer.get_last_advantages.remote()) - assert advantages is not None - # Per-group dispatch: each group is one sample → centered advantage is 0. - # The two microbatch calls are concatenated. - assert advantages.shape == (2, 6) - assert torch.allclose(advantages, torch.zeros((2, 6))) - - def test_rollout_pump_runs_concurrently_with_train(self, ray_init): - """rollout_pump dispatches while train_pump is sleeping. - - If pumps were sequential, rollout dispatches would only happen - between training steps. With concurrent asyncio tasks, rollout - dispatches happen while trainer is in asyncio.sleep(). - """ - dp_client = FakeDataPlaneActor.remote() - # Gen is fast (0.02s), trainer is slow (0.3s) - gen = DryRunGenWorker.remote(gen_latency_s=0.02) - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.3) - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - max_train_steps=2, - min_prompt_groups_per_batch=1, - generations_per_prompt=1, - max_buffered_rollouts=6, - max_inflight_prompts=6, - ) - - ray.get(ctrl.run.remote(), timeout=30) - - # Multiple rollouts should have completed during the first train step - call_timestamps = ray.get(gen.get_call_timestamps.remote()) - train_start_times = ray.get(trainer.get_train_start_times.remote()) - - assert len(call_timestamps) > 0 - assert len(train_start_times) > 0 - - # Some rollout calls should have started AFTER the first train step began - first_train_start = train_start_times[0] - rollouts_during_train = sum(1 for t in call_timestamps if t > first_train_start) - assert rollouts_during_train > 0, ( - "No rollouts dispatched while trainer was running — pumps may not be concurrent" - ) - - def test_buffer_capacity_semaphore_blocks_rollout(self, ray_init): - """_rollout_pump blocks when buffer capacity is exhausted. - - Set max_buffered_rollouts=2 with slow trainer — rollout_pump - should fill buffer capacity then block until trainer clears a group. - """ - dp_client = FakeDataPlaneActor.remote() - gen = DryRunGenWorker.remote(gen_latency_s=0.01) # fast gen - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.3) # slow trainer - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - max_train_steps=2, - min_prompt_groups_per_batch=1, - generations_per_prompt=1, - max_buffered_rollouts=2, # small buffer — backpressure kicks in - max_inflight_prompts=4, - ) - - start = time.monotonic() - result = ray.get(ctrl.run.remote(), timeout=30) - elapsed = time.monotonic() - start - - # Should complete without deadlock - assert result["train_steps"] == 2 - # DataPlane depth should never exceed max_buffered_rollouts (approx) - # We can't easily observe mid-run depth, but completion = no deadlock - - def test_rollout_permitted_pauses_during_sync(self, ray_init): - """_rollout_pump pauses new dispatches during _sync_weights. - - During weight sync, _rollout_permitted is cleared. _rollout_pump - blocks on _rollout_permitted.wait() so no new generate_and_push - calls are made. Existing in-flight ones drain naturally. - """ - dp_client = FakeDataPlaneActor.remote() - gen = DryRunGenWorker.remote(gen_latency_s=0.05) - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.05) - weight_sync = DryRunWeightSynchronizer(sync_latency_s=0.15) # slow sync - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - weight_sync=weight_sync, - max_train_steps=2, - min_prompt_groups_per_batch=1, - generations_per_prompt=1, - ) - - result = ray.get(ctrl.run.remote(), timeout=30) - assert result["train_steps"] == 2 - # Weight sync happened (sync_count > 0 implies gate opened correctly) - - def test_ping_returns_while_running(self, ray_init): - """ping() returns immediately if event loop is running — basis for watchdog.""" - dp_client = FakeDataPlaneActor.remote() - gen = DryRunGenWorker.remote(gen_latency_s=0.05) - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.1) - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - max_train_steps=5, - min_prompt_groups_per_batch=1, - generations_per_prompt=1, - ) - - # Start SC - run_ref = ctrl.run.remote() - - # Ping while SC is running — should return quickly - time.sleep(0.2) - ping_start = time.monotonic() - health = ray.get(ctrl.ping.remote(), timeout=5) - ping_elapsed = time.monotonic() - ping_start - - assert health["alive"] is True - assert ping_elapsed < 3.0, ( - f"ping() took {ping_elapsed:.2f}s — event loop may be blocked" - ) - - ray.get(run_ref, timeout=30) - - def test_staleness_sampler_filters_correctly(self): - """StalenessSampler returns freshest complete groups within the window.""" - buf = _buffer_with_versions([3, 4, 5, 2, 6]) - sampler = StalenessSampler( - buf, max_staleness_versions=2, sample_freshest_first=True - ) - - selected, num_groups = asyncio.run( - sampler.select(current_train_weight=5, min_prompt_groups=2) - ) - - assert selected is not None - # freshest-first: g2(lag 0), g1(lag 1). g3 stale, g4 future. - assert selected.sample_ids == ["g2_g0", "g1_g0"] - assert num_groups == 2 - - def test_staleness_sampler_returns_none_when_insufficient(self): - """StalenessSampler returns (None, 0) when not enough eligible rows.""" - buf = _buffer_with_versions([1]) - sampler = StalenessSampler(buf, max_staleness_versions=1) - - result = asyncio.run( - sampler.select(current_train_weight=5, min_prompt_groups=2) - ) - assert result == (None, 0) - - def test_staleness_sampler_concats_multiple_groups(self): - """Selected meta concatenates whole-group sample_ids end-to-end.""" - buf = _FakeBuffer() - buf.add("g0", weight=5, group_size=2) - buf.add("g1", weight=5, group_size=2) - sampler = StalenessSampler(buf, max_staleness_versions=0) - - selected, num_groups = asyncio.run( - sampler.select(current_train_weight=5, min_prompt_groups=2) - ) - assert selected is not None - assert selected.sample_ids == ["g0_g0", "g0_g1", "g1_g0", "g1_g1"] - assert num_groups == 2 - - def test_strict_on_policy_batch_sampler_requires_exact_version(self): - """Strict sampler waits for a full batch at the trainer version.""" - buf = _buffer_with_versions([4, 5, 5, 6]) - sampler = StalenessSampler(buf, max_staleness_versions=0) - - # Eligible at weight==5 are indices 1 and 2 only. - result = asyncio.run( - sampler.select(current_train_weight=5, min_prompt_groups=3) - ) - assert result == (None, 0) - - selected, num_groups = asyncio.run( - sampler.select(current_train_weight=5, min_prompt_groups=2) - ) - assert selected is not None - assert selected.sample_ids == ["g1_g0", "g2_g0"] - assert num_groups == 2 - - def test_strict_on_policy_batch_sampler_evicts_old_groups(self): - """Strict sampler drops complete old-version groups via buffer.remove.""" - buf = _buffer_with_versions([4, 5, 4]) - sampler = StalenessSampler(buf, max_staleness_versions=0) - - dropped = asyncio.run(sampler.evict(current_train_weight=5)) - - assert dropped == 2 - assert buf.weight_list == [5] - assert [m.sample_ids[0] for m in buf.meta_list] == ["g1_g0"] - - -class TestDryRunTrainerSplitAPI: - """Smoke test for DryRunTrainer split-API methods.""" - - def test_drytrainer_split_api_smoke(self, ray_init): - dp_client = FakeDataPlaneActor.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - meta = KVBatchMeta( - partition_id="rollout_data", - task_name="train", - sample_ids=["a", "b"], - ) - # Open step, microbatch, finish - ray.get(trainer.begin_train_step.remote("step-1")) - ray.get(trainer.train_microbatch_from_meta.remote("step-1", meta)) - ray.get(trainer.train_microbatch_from_meta.remote("step-1", meta)) - result = ray.get(trainer.finish_train_step.remote("step-1")) - assert result["trainer_version"] == 1 - assert ray.get(trainer.get_open_step_id.remote()) is None - assert ray.get(trainer.get_finish_calls.remote()) == ["step-1"] - mbs = ray.get(trainer.get_microbatch_calls.remote()) - assert len(mbs) == 2 - assert all(call[0] == "step-1" for call in mbs) - assert all(call[1] == ["a", "b"] for call in mbs) - # Abort then begin again - ray.get(trainer.begin_train_step.remote("step-2")) - ray.get(trainer.train_microbatch_from_meta.remote("step-2", meta)) - ray.get(trainer.abort_train_step.remote("step-2")) - assert ray.get(trainer.get_open_step_id.remote()) is None - assert ray.get(trainer.get_abort_calls.remote()) == ["step-2"] - # Trainer version did not advance via abort - ray.get(trainer.begin_train_step.remote("step-3")) - ray.get(trainer.finish_train_step.remote("step-3")) - # Now begin while a step is open should raise - ray.get(trainer.begin_train_step.remote("step-4")) - with pytest.raises(Exception): - ray.get(trainer.begin_train_step.remote("step-5")) - - -class TestStreamingTrainPump: - """Streaming train_pump end-to-end behavior under DryRunTrainer.""" - - def _make_controller( - self, - dp_client, - gen, - trainer, - prompts: list[str], - weight_sync=None, - max_train_steps=1, - min_prompt_groups_per_batch=1, - target_prompt_groups_per_step=4, - generations_per_prompt=1, - max_buffered_rollouts=8, - max_inflight_prompts=8, - max_weight_staleness_versions=1, - batch_selection_strategy="staleness_window", - max_num_epochs=1, - ): - mc = _make_test_master_config( - max_num_steps=max_train_steps, - min_prompt_groups_per_batch=min_prompt_groups_per_batch, - target_prompt_groups_per_step=target_prompt_groups_per_step, - num_generations_per_prompt=generations_per_prompt, - max_buffered_rollouts=max_buffered_rollouts, - max_inflight_prompts=max_inflight_prompts, - max_weight_staleness_versions=max_weight_staleness_versions, - batch_selection_strategy=batch_selection_strategy, - max_num_epochs=max_num_epochs, - ) - - # SC expects a StatefulDataLoader, but the pump only iterates it - # (`for prompt in self._dataloader`), so a list satisfies the contract. - dataloader = prompts - - if weight_sync is None: - weight_sync = DryRunWeightSynchronizer() - - tq_buffer = TQReplayBuffer( - dp_client, - partition_id="rollout_data", - pad_value_dict={"token_ids": 0}, - ) - rollout_manager = DryRunRolloutManager(gen, tq_buffer) - - bundle = SingleControllerBundle( - gen_handle=gen, - trainer_handle=trainer, - env_handles={}, - train_cluster=None, - inference_cluster=None, - dp_client=dp_client, - dataloader=dataloader, - weight_synchronizer=weight_sync, - advantage_estimator=None, - loss_fn=None, - rollout_manager=rollout_manager, - tq_buffer=tq_buffer, - partition_id="rollout_data", - ) - return SingleControllerActor.remote(master_config=mc, bundle=bundle) - - def test_streaming_dispatches_in_arrival_order(self, ray_init): - """SC dispatches train_microbatch in order groups commit at DP.""" - dp_client = FakeDataPlaneActor.remote() - # Group 0 slow, group 1 fast, group 2 medium → arrival order: 1, 2, 0 - gen = DryRunStaggeredGenWorker.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - prompts = ["0:0.30", "1:0.05", "2:0.15"] - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - prompts=prompts, - max_train_steps=1, - target_prompt_groups_per_step=3, - min_prompt_groups_per_batch=1, - ) - result = ray.get(ctrl.run.remote(), timeout=60) - assert result["train_steps"] == 1 - mbs = ray.get(trainer.get_microbatch_calls.remote()) - # 3 microbatches dispatched - assert len(mbs) == 3 - dispatched_groups = [call[1][0].split("_")[0] for call in mbs] - # group-0001 (fastest) before group-0002 (medium) before group-0000 (slow) - assert dispatched_groups == ["group-0001", "group-0002", "group-0000"] - - def test_trainer_version_advances_only_at_finish(self, ray_init): - """trainer_version stays put across mb calls; ticks on finish.""" - dp_client = FakeDataPlaneActor.remote() - gen = DryRunStaggeredGenWorker.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - prompts = [f"{i}:0.02" for i in range(4)] - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - prompts=prompts, - max_train_steps=1, - target_prompt_groups_per_step=4, - min_prompt_groups_per_batch=1, - ) - result = ray.get(ctrl.run.remote(), timeout=60) - assert result["train_steps"] == 1 - # trainer_version should be 1 (one finish_train_step call) - assert ray.get(trainer.get_trainer_version.remote()) == 1 - # finish was called exactly once - finishes = ray.get(trainer.get_finish_calls.remote()) - assert finishes == ["sc-step-000000"] - mbs = ray.get(trainer.get_microbatch_calls.remote()) - assert len(mbs) == 4 - - def test_strict_on_policy_rejects_stale_group_midstep(self, ray_init): - """Strict mode (staleness=0): group at version V-1 is not dispatched.""" - dp_client = FakeDataPlaneActor.remote() - # Pre-stage: stale group at version -1 (trainer starts at v=0, strict) - stale_meta = ray.get( - dp_client.put_samples.remote( - sample_ids=["stale_g0"], - partition_id="rollout_data", - fields=TensorDict( - {"input_ids": torch.ones((1, 3), dtype=torch.long)}, - batch_size=[1], - ), - tags=[ - { - "group_id": "stale", - "weight_version": -1, - "committed": True, - "expected_num_samples": 1, - } - ], - ) - ) - del stale_meta - gen = DryRunStaggeredGenWorker.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - prompts = [f"{i}:0.02" for i in range(2)] - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - prompts=prompts, - max_train_steps=1, - target_prompt_groups_per_step=2, - min_prompt_groups_per_batch=1, - batch_selection_strategy="strict_on_policy", - max_weight_staleness_versions=0, - ) - result = ray.get(ctrl.run.remote(), timeout=60) - assert result["train_steps"] == 1 - mbs = ray.get(trainer.get_microbatch_calls.remote()) - # The stale group was evicted by _evict_stale_claimed; never dispatched - all_sample_ids = [sid for _, ids, _ in mbs for sid in ids] - assert "stale_g0" not in all_sample_ids - - def test_long_tail_overlap(self, ray_init): - """First microbatch begins before the long-tail group's rollout finishes.""" - dp_client = FakeDataPlaneActor.remote() - # Group 0 fast, 1-3 medium, group 4 slow - gen = DryRunStaggeredGenWorker.remote() - trainer = DryRunTrainer.remote( - dp_client, train_latency_s=0.0, microbatch_latency_s=0.0 - ) - prompts = ["0:0.01", "1:0.03", "2:0.03", "3:0.03", "4:0.30"] - - ctrl = self._make_controller( - dp_client, - gen, - trainer, - prompts=prompts, - max_train_steps=1, - target_prompt_groups_per_step=5, - min_prompt_groups_per_batch=1, - ) - result = ray.get(ctrl.run.remote(), timeout=60) - assert result["train_steps"] == 1 - mbs = ray.get(trainer.get_microbatch_calls.remote()) - assert len(mbs) == 5 - first_mb_ts = mbs[0][2] - # generate() records call-time before sleep; derive completion via prompt latency. - call_ts = ray.get(gen.get_call_timestamps.remote()) - latencies = [float(p.split(":")[1]) for p in prompts] - completion_ts = [call_ts[i] + latencies[i] for i in range(len(prompts))] - slow_completion = max(completion_ts) - assert first_mb_ts < slow_completion, ( - f"first mb dispatched at {first_mb_ts} but slow group " - f"completed at {slow_completion}" - ) - - def test_abort_train_step_idempotent_and_clears_state(self, ray_init): - """abort_train_step clears state and a new begin succeeds.""" - dp_client = FakeDataPlaneActor.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - meta = KVBatchMeta( - partition_id="rollout_data", - task_name="train", - sample_ids=["a", "b"], - ) - ray.get(trainer.begin_train_step.remote("step-x")) - ray.get(trainer.train_microbatch_from_meta.remote("step-x", meta)) - ray.get(trainer.train_microbatch_from_meta.remote("step-x", meta)) - ray.get(trainer.abort_train_step.remote("step-x")) - assert ray.get(trainer.get_open_step_id.remote()) is None - # New begin must succeed - ray.get(trainer.begin_train_step.remote("step-y")) - assert ray.get(trainer.get_open_step_id.remote()) == "step-y" - # Idempotent: a second abort on a closed step also clears (no raise) - ray.get(trainer.abort_train_step.remote("step-y")) - assert ray.get(trainer.get_open_step_id.remote()) is None - ray.get(trainer.abort_train_step.remote("step-y")) - assert ray.get(trainer.get_open_step_id.remote()) is None - - def test_empty_step_is_no_op(self, ray_init): - """No rollouts → SC exits without calling finish_train_step.""" - dp_client = FakeDataPlaneActor.remote() - gen = DryRunStaggeredGenWorker.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - ctrl = self._make_controller( - dp_client, - gen, - trainer, - prompts=["0:0.01"], - max_train_steps=1, - target_prompt_groups_per_step=2, - min_prompt_groups_per_batch=1, - ) - result = ray.get(ctrl.run.remote(), timeout=30) - assert result["train_steps"] == 0 - assert ray.get(trainer.get_finish_calls.remote()) == [] - assert ray.get(trainer.get_microbatch_calls.remote()) == [] - - def test_clear_samples_called_once_per_step(self, ray_init): - """clear_samples is called exactly once per step covering all dispatched ids.""" - dp_client = FakeDataPlaneActor.remote() - gen = DryRunStaggeredGenWorker.remote() - trainer = DryRunTrainer.remote(dp_client, train_latency_s=0.0) - prompts = ["0:0.01", "1:0.02", "2:0.03"] - ctrl = self._make_controller( - dp_client, - gen, - trainer, - prompts=prompts, - max_train_steps=1, - target_prompt_groups_per_step=3, - min_prompt_groups_per_batch=1, - ) - result = ray.get(ctrl.run.remote(), timeout=60) - assert result["train_steps"] == 1 - clear_calls = ray.get(dp_client.get_clear_calls.remote()) - assert len(clear_calls) == 1 - mbs = ray.get(trainer.get_microbatch_calls.remote()) - dispatched_ids = set() - for _, ids, _ in mbs: - dispatched_ids.update(ids) - assert set(clear_calls[0]) == dispatched_ids - - -class TestRisk06EventLoopBlocking: - """RISK-06: validate that asyncio event loop is not blocked during training. - - The risk: if train_from_meta is a synchronous blocking call, the asyncio - event loop freezes and _rollout_pump + _sync_weights can't make progress. - Fix: use `await loop.run_in_executor(None, blocking_fn, ...)` or ensure - train_from_meta is an async method (as DryRunTrainer is). - - These tests document the expected behavior and serve as a benchmark. - """ - - def test_blocking_call_freezes_loop(self): - """Demonstrate that a synchronous time.sleep freezes the event loop. - - This test validates the PROBLEM (not the solution) — if train used - time.sleep instead of asyncio.sleep, other tasks would not progress. - """ - progress: list[str] = [] - - async def blocking_task(): - progress.append("blocking_start") - time.sleep(0.1) # blocks event loop - progress.append("blocking_end") - - async def concurrent_task(): - progress.append("concurrent_start") - await asyncio.sleep(0) - progress.append("concurrent_mid") - await asyncio.sleep(0) - progress.append("concurrent_end") - - async def run(): - t1 = asyncio.create_task(blocking_task()) - t2 = asyncio.create_task(concurrent_task()) - await asyncio.gather(t1, t2) - - asyncio.run(run()) - - # With blocking call, concurrent task can't interleave during the sleep - # blocking_start, blocking_end happen before concurrent_mid - block_end_idx = progress.index("blocking_end") - concurrent_mid_idx = progress.index("concurrent_mid") - assert block_end_idx < concurrent_mid_idx, ( - "blocking_task did not freeze concurrent_task as expected" - ) - - def test_async_sleep_allows_concurrency(self): - """Demonstrate that asyncio.sleep yields to other tasks. - - The DryRunTrainer uses asyncio.sleep — this shows the event loop - stays responsive during 'training'. Production code must use - loop.run_in_executor() for real blocking GPU operations. - """ - progress: list[str] = [] - - async def async_task(): - progress.append("async_start") - await asyncio.sleep(0.1) # yields to event loop - progress.append("async_end") - - async def concurrent_task(): - progress.append("concurrent_start") - await asyncio.sleep(0.01) - progress.append("concurrent_mid") - await asyncio.sleep(0) - progress.append("concurrent_end") - - async def run(): - t1 = asyncio.create_task(async_task()) - t2 = asyncio.create_task(concurrent_task()) - await asyncio.gather(t1, t2) - - asyncio.run(run()) - - # concurrent_task should make progress while async_task is sleeping - async_end_idx = progress.index("async_end") - concurrent_mid_idx = progress.index("concurrent_mid") - assert concurrent_mid_idx < async_end_idx, ( - "concurrent_task should have progressed while async_task was sleeping" - ) - - def test_run_in_executor_unblocks_loop(self): - """Validate the production fix for RISK-06. - - In production, policy.train() is a blocking GPU call. SC must use: - await loop.run_in_executor(None, policy.train, ...) - This runs the blocking call in a thread pool, leaving the event loop - free for _rollout_pump and _sync_weights to make progress. - """ - progress: list[str] = [] - - def blocking_train(): - time.sleep(0.1) - return "trained" - - async def train_with_executor(): - loop = asyncio.get_running_loop() - progress.append("train_start") - result = await loop.run_in_executor(None, blocking_train) - progress.append("train_end") - return result - - async def rollout(): - progress.append("rollout_start") - await asyncio.sleep(0.02) - progress.append("rollout_mid") - await asyncio.sleep(0.02) - progress.append("rollout_end") - - async def run(): - t1 = asyncio.create_task(train_with_executor()) - t2 = asyncio.create_task(rollout()) - await asyncio.gather(t1, t2) - - asyncio.run(run()) - - # rollout should have made progress WHILE train was blocking in executor - train_end_idx = progress.index("train_end") - rollout_mid_idx = progress.index("rollout_mid") - assert rollout_mid_idx < train_end_idx, ( - "rollout should have progressed while blocking_train ran in executor" - ) diff --git a/tests/unit/single_controller/test_single_controller_setup.py b/tests/unit/single_controller/test_single_controller_setup.py index 7dd8277962d..1ca6817ef83 100644 --- a/tests/unit/single_controller/test_single_controller_setup.py +++ b/tests/unit/single_controller/test_single_controller_setup.py @@ -1,9 +1,10 @@ -"""Unit tests for nemo_rl.algorithms.single_controller_utils.setup. +"""Unit tests for setup_single_controller. -setup is heavy (it spins up Ray clusters, TQPolicy, generation backend, ...) so it's -exercised through monkey-patching rather than as a real e2e — the unit tests cover the -shape of the contract, not the underlying initialization. The full path is covered by -the functional test at tests/functional/grpo_dp_single_controller.sh. +setup_single_controller is heavy (it spins up Ray clusters, TQPolicy, generation +backend, ...) so it's exercised through monkey-patching rather than as a real e2e — +the unit tests cover the shape of the contract, not the underlying initialization. +The full path is covered by the functional test at +tests/functional/grpo_dp_single_controller.sh. """ from __future__ import annotations @@ -12,12 +13,13 @@ import pytest +import nemo_rl.algorithms.single_controller_utils.setup as sc_setup_mod +from nemo_rl.algorithms.loss import ClippedPGLossConfig from nemo_rl.algorithms.single_controller_utils import ( MasterConfig, SingleControllerBundle, - setup, + setup_single_controller, ) -from nemo_rl.algorithms.single_controller_utils import setup as setup_module def _make_master_config( @@ -61,6 +63,7 @@ def _make_master_config( "colocated": {"enabled": colocated, "resources": {}}, }, }, + loss_fn=ClippedPGLossConfig(), env=env if env is not None else {}, ) @@ -80,17 +83,17 @@ def patched_factories(): with ( patch.object( - setup_module, + sc_setup_mod, "setup_response_data", return_value=(fake_dataset, None, fake_env_handles, {}), ) as mock_setup_response, patch.object( - setup_module, + sc_setup_mod, "StatefulDataLoader", return_value=fake_dataloader, ) as mock_dataloader, patch.object( - setup_module, + sc_setup_mod, "_build_clusters", return_value=( MagicMock(name="train_cluster"), @@ -98,31 +101,31 @@ def patched_factories(): ), ) as mock_clusters, patch.object( - setup_module, "_build_generation", return_value=MagicMock(name="gen") + sc_setup_mod, "_build_generation", return_value=MagicMock(name="gen") ) as mock_gen, patch.object( - setup_module, "_build_trainer", return_value=MagicMock(name="policy") + sc_setup_mod, "_build_trainer", return_value=MagicMock(name="policy") ) as mock_trainer, patch.object( - setup_module, + sc_setup_mod, "build_data_plane_client", return_value=MagicMock(name="dp_client"), ) as mock_dp_client, patch.object( - setup_module, + sc_setup_mod, "create_weight_synchronizer", return_value=MagicMock(name="weight_sync"), ) as mock_weight_sync, patch.object( - setup_module, + sc_setup_mod, "_create_advantage_estimator", return_value=MagicMock(name="adv"), ) as mock_adv, patch.object( - setup_module, "ClippedPGLossFn", return_value=MagicMock(name="loss_fn") + sc_setup_mod, "ClippedPGLossFn", return_value=MagicMock(name="loss_fn") ) as mock_loss, patch.object( - setup_module, + sc_setup_mod, "_generation_max_seq_len", return_value=32, ), @@ -148,18 +151,18 @@ class TestSetup: def test_raises_when_data_plane_disabled(self): mc = _make_master_config(dp_enabled=False) with pytest.raises(ValueError, match="data_plane.enabled=True"): - setup(mc, MagicMock()) + setup_single_controller(mc, MagicMock()) def test_multiple_dataloader_not_supported(self): mc = _make_master_config(use_multiple_dataloader=True) with pytest.raises(NotImplementedError, match="use_multiple_dataloader"): - setup(mc, MagicMock(pad_token_id=0)) + setup_single_controller(mc, MagicMock(pad_token_id=0)) def test_returns_bundle(self, patched_factories): mc = _make_master_config(colocated=True) tokenizer = MagicMock(pad_token_id=0) - bundle = setup(mc, tokenizer) + bundle = setup_single_controller(mc, tokenizer) assert isinstance(bundle, SingleControllerBundle) assert bundle.gen_handle is patched_factories["_build_generation"].return_value @@ -192,7 +195,7 @@ def test_env_handles_sourced_from_setup_response_data(self, patched_factories): math_env_cfg = {"some": "value"} mc = _make_master_config(env={"math": math_env_cfg}) - bundle = setup(mc, MagicMock(pad_token_id=0)) + bundle = setup_single_controller(mc, MagicMock(pad_token_id=0)) _, call_kwargs = patched_factories["setup_response_data"].call_args assert call_kwargs["env_configs"] == {"math": math_env_cfg} @@ -203,7 +206,7 @@ def test_weight_sync_factory_args(self, patched_factories): mc = _make_master_config(colocated=False, backend="vllm") tokenizer = MagicMock(pad_token_id=0) - setup(mc, tokenizer) + setup_single_controller(mc, tokenizer) _, factory_kwargs = patched_factories["create_weight_synchronizer"].call_args assert ( @@ -220,7 +223,7 @@ def test_custom_partition_id(self, patched_factories): mc = _make_master_config() tokenizer = MagicMock(pad_token_id=7) - bundle = setup(mc, tokenizer, partition_id="custom_partition") + bundle = setup_single_controller(mc, tokenizer, partition_id="custom_partition") assert bundle.partition_id == "custom_partition" assert bundle.tq_buffer._partition_id == "custom_partition" @@ -237,7 +240,7 @@ def test_megatron_train_iters_capped_by_max_num_steps(self, patched_factories): max_num_epochs=1, ) # patched dataloader has len() == 4, so the min picks max_num_steps. - setup(mc, MagicMock(pad_token_id=0)) + setup_single_controller(mc, MagicMock(pad_token_id=0)) assert mc.policy["megatron_cfg"]["train_iters"] == 2 @@ -249,12 +252,12 @@ def test_megatron_train_iters_capped_by_dataloader_epochs(self, patched_factorie max_num_epochs=2, ) # patched dataloader has len() == 4 → 2 * 4 = 8 < 1000. - setup(mc, MagicMock(pad_token_id=0)) + setup_single_controller(mc, MagicMock(pad_token_id=0)) assert mc.policy["megatron_cfg"]["train_iters"] == 8 def test_megatron_train_iters_not_set_when_disabled(self, patched_factories): mc = _make_master_config(megatron_enabled=False) - setup(mc, MagicMock(pad_token_id=0)) + setup_single_controller(mc, MagicMock(pad_token_id=0)) assert "train_iters" not in mc.policy.get("megatron_cfg", {}) diff --git a/tests/unit/single_controller/test_tq_replay_buffer.py b/tests/unit/single_controller/test_tq_replay_buffer.py index 162c07ac14f..95197e6ff0c 100644 --- a/tests/unit/single_controller/test_tq_replay_buffer.py +++ b/tests/unit/single_controller/test_tq_replay_buffer.py @@ -147,30 +147,6 @@ def test_add_writes_tq_then_appends_meta(self): assert meta.tags == [{"weight_version": 3}] * _N_GENS assert len(dp.put_calls) == 1 - def test_add_rejects_non_int_weight_version(self): - dp = FakeDataPlaneClient() - buf = _make_buffer(dp) - with pytest.raises(TypeError): - _run( - buf.add( - _make_record(), - weight_version=None, # type: ignore[arg-type] - ) - ) - assert dp.depth() == 0 - assert buf.size() == 0 - - def test_add_rejects_bool_weight_version(self): - dp = FakeDataPlaneClient() - buf = _make_buffer(dp) - with pytest.raises(TypeError): - _run( - buf.add( - _make_record(), - weight_version=True, # type: ignore[arg-type] - ) - ) - def test_add_appends_multiple_records_in_order(self): dp = FakeDataPlaneClient() buf = _make_buffer(dp) From 04b37886469bb54fbe5e5303d5945bb48260df7e Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Mon, 15 Jun 2026 06:38:23 -0700 Subject: [PATCH 07/44] feat(single-controller): add over_sampling=false batch-quota mode via reserve/commit slots Signed-off-by: Yuki Huang update unit test Signed-off-by: Yuki Huang --- .../grpo_math_1B_single_controller.yaml | 5 + .../algorithms/async_utils/replay_buffer.py | 73 +- .../async_utils/staleness_sampler.py | 58 +- nemo_rl/algorithms/single_controller.py | 76 +- .../single_controller_utils/config.py | 3 + nemo_rl/experience/rollout_manager.py | 20 +- tests/unit/experience/test_rollout_manager.py | 795 ++++++++++++++++++ tests/unit/experience/test_rollouts.py | 550 ------------ .../single_controller/test_rollout_pump.py | 4 +- .../test_staleness_sampler.py | 130 ++- .../test_tq_replay_buffer.py | 109 ++- 11 files changed, 1182 insertions(+), 641 deletions(-) create mode 100644 tests/unit/experience/test_rollout_manager.py diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml index 2054a51dbc1..11736772e7d 100644 --- a/examples/configs/grpo_math_1B_single_controller.yaml +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -343,7 +343,12 @@ async_rl: target_prompt_groups_per_step: null # falls back to min_prompt_groups_per_batch batch_selection_strategy: "strict_on_policy" # or "staleness_window" max_inflight_prompts: 8 + # When over_sampling=false this must equal + # target_prompt_groups_per_step * (max_weight_staleness_versions + 1). max_buffered_rollouts: 8 + # True : over-generates and wastes rollouts that age past the staleness window; + # False: enforces per-weight-version dispatch quota. + over_sampling: true cluster: gpus_per_node: 2 diff --git a/nemo_rl/algorithms/async_utils/replay_buffer.py b/nemo_rl/algorithms/async_utils/replay_buffer.py index b782e0ec793..bc3ef251af2 100644 --- a/nemo_rl/algorithms/async_utils/replay_buffer.py +++ b/nemo_rl/algorithms/async_utils/replay_buffer.py @@ -558,10 +558,10 @@ class ReplayBuffer(ReplayBufferImpl): class TQReplayBuffer: - """Meta cache + TQ writer for prompt-group records. + """Meta cache + TQ writer with reserve-then-commit slot semantics. - add tensorizes one record and writes its N rows to TQ as a single group; - meta_list / weight_list keep one entry per group for sampler reads. + meta_list, weight_list, ready_list, _group_ids are parallel; a slot stays + ready=False until commit fills it. """ def __init__( @@ -574,32 +574,56 @@ def __init__( self._dp_client = dp_client self._partition_id = partition_id self._pad_value_dict = dict(pad_value_dict) - self.meta_list: list[KVBatchMeta] = [] - self.weight_list: list[int] = [] + self.meta_list: list[Optional[KVBatchMeta]] = [] + self.start_weight_list: list[int] = [] + self.end_weight_list: list[int] = [] + self.ready_list: list[bool] = [] + self._group_ids: list[str] = [] - async def add( - self, - record: PromptGroupRecord, - *, - weight_version: int, - group_id: Optional[str] = None, - ) -> KVBatchMeta: - """Tensorize record and write its N rows to TQ as one group. + def reserve(self, *, weight_version: int, group_id: Optional[str] = None) -> str: + """Append an unready slot tagged with weight_version. Args: - record: PromptGroupRecord with N completions to tensorize. - weight_version: Trainer weight version stamped on every row's tag; must be int. + weight_version: Weight version stamped on the slot. group_id: Per-group sample_id prefix; defaults to a fresh uuid4. Returns: - KVBatchMeta for the newly written group. + group_id used by the matching commit. """ if group_id is None: group_id = str(uuid.uuid4()) + self.meta_list.append(None) + self.start_weight_list.append(weight_version) + self.end_weight_list.append(-1) + self.ready_list.append(False) + self._group_ids.append(group_id) + return group_id + + async def commit( + self, + group_id: str, + record: PromptGroupRecord, + start_weight_version: int, + end_weight_version: int, + ) -> KVBatchMeta: + """Tensorize record, write N rows to TQ, and mark the slot ready. + + Args: + group_id: group_id returned by the matching reserve call. + record: PromptGroupRecord to tensorize. + start_weight_version: Weight version stamped on the slot before rollout. + The same as the one from reserve, passed again to avoid race condition when lookup. + end_weight_version: Weight version stamped on the slot after rollout. + Returns: + KVBatchMeta for the committed group. + + Raises: + ValueError: group_id has no live slot (removed or never reserved). + """ train_batch = record_to_train_batch(record, pad_value_dict=self._pad_value_dict) sample_ids, fields, tags = pack_payload( - train_batch, weight_version=weight_version, group_id=group_id + train_batch, weight_version=start_weight_version, group_id=group_id ) await self._call_dp( "put_samples", @@ -620,8 +644,10 @@ async def add( tags=[dict(t) for t in tags], ) - self.meta_list.append(meta) - self.weight_list.append(weight_version) + idx = self._group_ids.index(group_id) + self.meta_list[idx] = meta + self.end_weight_list[idx] = end_weight_version + self.ready_list[idx] = True return meta async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: @@ -646,9 +672,14 @@ async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: dropped_sample_ids: list[str] = [] for i in drop_idxs: - dropped_sample_ids.extend(self.meta_list[i].sample_ids) + meta = self.meta_list[i] + if meta is not None: + dropped_sample_ids.extend(meta.sample_ids) del self.meta_list[i] - del self.weight_list[i] + del self.start_weight_list[i] + del self.end_weight_list[i] + del self.ready_list[i] + del self._group_ids[i] if remove_in_dp: await self._call_dp( diff --git a/nemo_rl/algorithms/async_utils/staleness_sampler.py b/nemo_rl/algorithms/async_utils/staleness_sampler.py index 390529b4a10..63d5f19225b 100644 --- a/nemo_rl/algorithms/async_utils/staleness_sampler.py +++ b/nemo_rl/algorithms/async_utils/staleness_sampler.py @@ -21,7 +21,9 @@ class StalenessSampler: """Pick complete prompt groups inside a version staleness window. - Defaults to FIFO (sample_freshest_first=False); pass True to prefer smallest lag. + sample_freshest_first prefers smallest lag; require_order takes only from + the oldest weight_version present and waits for its batch to fill. Unready + slots are always skipped. """ def __init__( @@ -29,15 +31,21 @@ def __init__( buffer: TQReplayBuffer, max_staleness_versions: int, sample_freshest_first: bool = False, + require_order: bool = False, ) -> None: if max_staleness_versions < 0: raise ValueError( f"max_staleness_versions must be non-negative, got " f"{max_staleness_versions}" ) + if require_order and sample_freshest_first: + raise ValueError( + "require_order and sample_freshest_first are mutually exclusive" + ) self._buffer = buffer self.max_staleness_versions = max_staleness_versions self.sample_freshest_first = sample_freshest_first + self.require_order = require_order async def select( self, @@ -45,38 +53,54 @@ async def select( current_train_weight: int, min_prompt_groups: int, ) -> tuple[KVBatchMeta | None, int]: - """Return a concat of the first min_prompt_groups eligible groups, or None. + """Concat the first min_prompt_groups eligible groups and drop them from the buffer. - Freshest-first (smallest lag, ties by insertion order) when - sample_freshest_first is set, else insertion-order FIFO. - Selected entries are dropped from the buffer locally; DataPlane rows survive - for the trainer and are cleared by the caller at step boundary. + Eligibility = ready and weight in + [current_train_weight - max_staleness_versions, current_train_weight]. + DataPlane rows survive the local drop; caller clears them at step boundary. Args: - current_train_weight: Current trainer weight version. Eligibility window is - [current_train_weight - max_staleness_versions, current_train_weight]. + current_train_weight: Current trainer weight version. min_prompt_groups: Minimum groups required; returns (None, 0) below this. Returns: - meta: Concatenated KVBatchMeta covering num_groups groups, or None. + meta: Concatenated KVBatchMeta, or None if not enough groups. num_groups: Number of prompt groups in meta; 0 when meta is None. """ if min_prompt_groups < 1: raise ValueError(f"min_prompt_groups must be >= 1, got {min_prompt_groups}") min_valid_version = max(0, current_train_weight - self.max_staleness_versions) - valid_idxs = [ - i - for i, weight in enumerate(self._buffer.weight_list) - if min_valid_version <= weight <= current_train_weight - ] + + if self.require_order: + in_window = [ + weight + for weight in self._buffer.start_weight_list + if min_valid_version <= weight <= current_train_weight + ] + if not in_window: + return None, 0 + target_version = min(in_window) + valid_idxs = [ + i + for i, weight in enumerate(self._buffer.start_weight_list) + if weight == target_version and self._buffer.ready_list[i] + ] + else: + valid_idxs = [ + i + for i, weight in enumerate(self._buffer.start_weight_list) + if min_valid_version <= weight <= current_train_weight + and self._buffer.ready_list[i] + ] + if len(valid_idxs) < min_prompt_groups: return None, 0 if self.sample_freshest_first: valid_idxs.sort( key=lambda i: ( - current_train_weight - self._buffer.weight_list[i], + current_train_weight - self._buffer.start_weight_list[i], i, ) ) @@ -87,7 +111,7 @@ async def select( await self._buffer.remove(selected_idxs, remove_in_dp=False) return ( - selected_metas[0].concat(*selected_metas[1:]), + selected_metas[0].concat(*selected_metas[1:]), # type: ignore len(selected_idxs), ) @@ -106,7 +130,7 @@ async def evict(self, *, current_train_weight: int) -> int: min_valid_version = max(0, current_train_weight - self.max_staleness_versions) stale_idxs = [ i - for i, weight in enumerate(self._buffer.weight_list) + for i, weight in enumerate(self._buffer.start_weight_list) if weight < min_valid_version ] if not stale_idxs: diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 4472afe4b9c..dfde1eac0ff 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -20,8 +20,9 @@ Data flow: _rollout_pump → rollout_manager.generate_and_push(prompt) - → TQReplayBuffer.add tensorizes the record and writes - N training rows to TQ as one prompt-group. + → TQReplayBuffer.reserve claims a slot at dispatch time; + run_rollout runs; TQReplayBuffer.commit tensorizes the + record, writes N training rows to TQ, and marks ready. _train_pump → sampler.evict → buffer.remove (stale groups, with DP clear). → sampler.select → drops chosen groups from buffer, returns KVBatchMeta of K groups (or None); meta is already trainable. @@ -57,7 +58,8 @@ class SingleControllerActor: """CPU-only Ray actor that orchestrates the RL training loop. Owns three concurrent asyncio tasks: - - _rollout_pump: dispatches prompts via RolloutManager → TQReplayBuffer.add + - _rollout_pump: dispatches prompts via RolloutManager; reserve+commit in + TQReplayBuffer preserves dispatch order - _train_pump: evicts stale groups, samples a batch, trains, drops it - _sync_weights: drain gate + weight synchronization @@ -120,9 +122,22 @@ def __init__( flush=True, ) + if not self._async_cfg.over_sampling: + expected_buffer = self._async_cfg.target_prompt_groups_per_step * ( + self._async_cfg.max_weight_staleness_versions + 1 + ) + if self._async_cfg.max_buffered_rollouts != expected_buffer: + raise ValueError( + f"over_sampling=False requires max_buffered_rollouts " + f"({self._async_cfg.max_buffered_rollouts}) == " + f"target_prompt_groups_per_step * (max_weight_staleness_versions + 1) " + f"({expected_buffer})" + ) + self._sampler = StalenessSampler( self._buffer, max_staleness_versions=self._async_cfg.max_weight_staleness_versions, + require_order=not self._async_cfg.over_sampling, ) # ── asyncio state ────────────────────────────────────────────────── @@ -133,6 +148,10 @@ def __init__( # Count of in-flight generate_and_push calls self._inflight_rollouts: int = 0 + # over_sampling=False batch gate: farthest trainer_version covered by + # already-dispatched batches. + self._max_rollout_version: int = -1 + # Backpressure valve: max unconsumed rollout groups allowed in DataPlane. # Acquired before each rollout dispatch; released when the buffer # drops a group (sampler.evict or post-train buffer.remove). @@ -149,6 +168,7 @@ def __init__( f"staleness_cap={self._async_cfg.max_weight_staleness_versions} " f"buffer={self._async_cfg.max_buffered_rollouts} " f"inflight={self._async_cfg.max_inflight_prompts} " + f"over_sampling={self._async_cfg.over_sampling} " f"transport={self._weight_sync_cfg.transport}", flush=True, ) @@ -202,21 +222,25 @@ async def _call_dp(self, method_name: str, **kwargs) -> Any: # ── the three pumps + advantage helper ──────────────────────────────── - # TODO @yukih: rollout_pump only gates on buffer_capacity, not on the current step's group quota. - # e.g. max_staleness_versions=0, gbs=16, groups generated past the step's 16 become stale at the next weight sync and get evicted — wasted GPU. async def _rollout_pump(self) -> None: """Continuously dispatch rollout tasks until cancellation. - Flow per prompt: + Per batch (over_sampling=False): + 0. Wait while _max_rollout_version >= trainer_version + max_staleness, + then claim the next step by incrementing _max_rollout_version. + + Per prompt: 1. Acquire _buffer_capacity slot (backpressure) 2. Acquire sem (cap concurrent in-flight rollouts) 3. Wait for _rollout_permitted (paused during weight sync) 4. Call rollout_manager.generate_and_push(prompt) — local async - RolloutManager runs the rollout and writes the group via - TQReplayBuffer.add (→ dp_client.put_samples + meta append) + RolloutManager reserves a slot, runs the rollout, then commits the + group via TQReplayBuffer (→ dp_client.put_samples + mark ready) 5. Decrement _inflight_rollouts """ sem = asyncio.Semaphore(self._async_cfg.max_inflight_prompts) + over_sampling = self._async_cfg.over_sampling + max_staleness = self._async_cfg.max_weight_staleness_versions print("rollout_pump: starting", flush=True) async def _dispatch_one_prompt(prompt: DatumSpec) -> None: @@ -239,6 +263,15 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: epoch = 0 while max_epochs is None or epoch < max_epochs: for prompt_batch in self._dataloader: + # over_sampling=False: batch-level gate on max_rollout_version. + if not over_sampling: + while ( + self._max_rollout_version + >= self._trainer_version + max_staleness + ): + await asyncio.sleep(0.005) + self._max_rollout_version += 1 + for prompt_idx in range(prompt_batch.size): prompt: DatumSpec = { # type: ignore k: v[prompt_idx] for k, v in prompt_batch.items() @@ -375,19 +408,20 @@ async def _sync_weights(self) -> None: """ self._rollout_permitted.clear() - # Drain: wait for all in-flight rollouts to complete before NCCL - # Critical: if GenWorker has queued calls when NCCL init is dispatched, - # the init sits behind them — trainer blocks in rendezvous → deadlock - drain_start = time.monotonic() - while self._inflight_rollouts > 0: - await asyncio.sleep(0.005) - - drain_elapsed = time.monotonic() - drain_start - print( - f" _sync_weights: drained in {drain_elapsed:.3f}s, " - f"syncing weights v{self._trainer_version}", - flush=True, - ) + # TODO: currently sync_weights is not implemented, comment out for now + # # Drain: wait for all in-flight rollouts to complete before NCCL + # # Critical: if GenWorker has queued calls when NCCL init is dispatched, + # # the init sits behind them — trainer blocks in rendezvous → deadlock + # drain_start = time.monotonic() + # while self._inflight_rollouts > 0: + # await asyncio.sleep(0.005) + + # drain_elapsed = time.monotonic() - drain_start + # print( + # f" _sync_weights: drained in {drain_elapsed:.3f}s, " + # f"syncing weights v{self._trainer_version}", + # flush=True, + # ) t0 = time.monotonic() # TODO: currently sync_weights is not implemented, comment out for now diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py index 270a7f0b823..53bd1aa0e1e 100644 --- a/nemo_rl/algorithms/single_controller_utils/config.py +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -42,6 +42,9 @@ class AsyncRLConfig(BaseModel, extra="allow"): # Pump concurrency caps. max_inflight_prompts: int = 8 max_buffered_rollouts: int = 8 + # True : over-generates and wastes rollouts that age past the staleness window; + # False: enforces per-weight-version dispatch quota. + over_sampling: bool = True class MasterConfig(BaseModel, extra="allow"): diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 56dfcd9dd24..83b9d09a72b 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -581,12 +581,6 @@ def _compute_rollout_metrics( return rollout_metrics -# TODO(SC): -# 1. Turn RolloutManager into a Ray actor. -# 2. Keep policy_generation driver-constructed and pass it in (don't -# build it inside the rollout actor — avoids nested Ray actors). -# 3. Construct the rollout actor in setup_single_controller and -# drop the inline RolloutManager construction there. class RolloutManager: """Routes to AsyncRolloutImpl (native async) or AsyncNemoGymRolloutImpl (NeMo-Gym), and pushes results to a TQReplayBuffer.""" @@ -645,7 +639,7 @@ async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: return await self._impl.run_rollout(input_sample) async def generate_and_push(self, input_sample: DatumSpec) -> None: - """Run one prompt's rollout and write the N completions through the buffer. + """Reserve a buffer slot, run one prompt's rollout, then commit the slot. Args: input_sample: A single prompt (one DatumSpec entry). @@ -653,5 +647,15 @@ async def generate_and_push(self, input_sample: DatumSpec) -> None: assert self._tq_buffer is not None, ( "generate_and_push requires tq_buffer to be set at __init__" ) + start_version = self._weight_version + group_id = self._tq_buffer.reserve(weight_version=start_version) + record = await self.run_rollout(input_sample) - await self._tq_buffer.add(record, weight_version=self._weight_version) + end_version = self._weight_version + + await self._tq_buffer.commit( + group_id, + record, + start_weight_version=start_version, + end_weight_version=end_version, + ) diff --git a/tests/unit/experience/test_rollout_manager.py b/tests/unit/experience/test_rollout_manager.py new file mode 100644 index 00000000000..0542d1a6513 --- /dev/null +++ b/tests/unit/experience/test_rollout_manager.py @@ -0,0 +1,795 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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 RolloutManager. + +Two groups: + +* TestGenerateAndPushFlow — lightweight unit tests for the reserve→run→commit + flow in generate_and_push (no Ray/vLLM; fakes for impl + tq_buffer). +* AsyncRollout / AsyncNemoGymRollout tests — vLLM/Ray-backed end-to-end checks + for the underlying run_rollout paths (AsyncRolloutImpl / AsyncNemoGymRolloutImpl). +""" + +from __future__ import annotations + +import asyncio +import json +import tempfile +import uuid +from copy import deepcopy + +import pytest +import torch + +from nemo_rl.data.collate_fn import rl_collate_fn +from nemo_rl.data.datasets.response_datasets import NemoGymDataset +from nemo_rl.data.interfaces import DatumSpec +from nemo_rl.data.processors import nemo_gym_data_processor +from nemo_rl.distributed.batched_data_dict import BatchedDataDict +from nemo_rl.experience.interfaces import Completion, PromptGroupRecord +from nemo_rl.experience.rollout_manager import RolloutManager +from nemo_rl.experience.rollouts import ( + run_async_multi_turn_rollout, + run_async_nemo_gym_rollout, +) + +# Fixtures shared with the heavyweight rollout tests. +from tests.unit.environments.test_nemo_gym import ( + cluster, # noqa: F401 + nemo_gym, # noqa: F401 + nemo_gym_sanity_test_data, # noqa: F401 + nemo_gym_tokenizer, # noqa: F401 + nemo_gym_vllm_generation, # noqa: F401 +) +from tests.unit.experience.test_rollouts import ( + initial_multi_step_calculator_batch, # noqa: F401 + multi_step_calculator_environment, # noqa: F401 + multi_step_setup_vllm_async, # noqa: F401 + rollout_cluster, # noqa: F401 + rollout_tokenizer, # noqa: F401 +) +from tests.unit.test_envs import MultiStepCalcMetadata + + +def _run(coro): + return asyncio.run(coro) + + +class _FakeBuffer: + """Minimal TQReplayBuffer stand-in that records reserve/commit calls.""" + + def __init__(self) -> None: + self.reserve_calls: list[int] = [] # weight_versions passed to reserve + self.commit_calls: list[tuple[str, object, int, int]] = [] + # reserve(weight_version=X) -> group_id; commit fills the slot. + self._slots: list[str] = [] + + def reserve(self, *, weight_version: int, group_id: str | None = None) -> str: + if group_id is None: + group_id = str(uuid.uuid4()) + self.reserve_calls.append(weight_version) + self._slots.append(group_id) + return group_id + + async def commit( + self, + group_id: str, + record, + start_weight_version: int, + end_weight_version: int, + ): + self.commit_calls.append( + (group_id, record, start_weight_version, end_weight_version) + ) + return record + + +class _FakeImpl: + """Stand-in for AsyncRolloutImpl that returns a sentinel record.""" + + def __init__(self, record="sentinel-record", on_run=None) -> None: + self._record = record + self._on_run = on_run + + async def run_rollout(self, input_sample): + if self._on_run is not None: + await self._on_run(input_sample) + return self._record + + +def _make_manager(buffer: _FakeBuffer, impl: _FakeImpl) -> RolloutManager: + """Build a RolloutManager without firing the real __init__.""" + mgr = object.__new__(RolloutManager) + mgr._impl = impl + mgr._tokenizer = None + mgr._num_generations_per_prompt = 1 + mgr._tq_buffer = buffer + mgr._weight_version = 0 + return mgr + + +class TestGenerateAndPushFlow: + def test_reserves_then_runs_then_commits(self): + events: list[str] = [] + buf = _FakeBuffer() + + async def _track_run(_sample): + events.append("run") + + impl = _FakeImpl(record="r0", on_run=_track_run) + mgr = _make_manager(buf, impl) + + # Wrap reserve/commit to log ordering. + original_reserve = buf.reserve + original_commit = buf.commit + + def _logged_reserve(**kwargs): + events.append("reserve") + return original_reserve(**kwargs) + + async def _logged_commit(*args, **kwargs): + events.append("commit") + return await original_commit(*args, **kwargs) + + buf.reserve = _logged_reserve # type: ignore[method-assign] + buf.commit = _logged_commit # type: ignore[method-assign] + + _run(mgr.generate_and_push({"prompt": "p"})) + + assert events == ["reserve", "run", "commit"] + assert buf.reserve_calls == [0] + assert len(buf.commit_calls) == 1 + gid, record, start_v, end_v = buf.commit_calls[0] + assert gid in buf._slots + assert record == "r0" + assert start_v == 0 + assert end_v == 0 + + def test_start_weight_version_pinned_at_reserve_time(self): + """If set_weight_version is called mid-rollout, start != end.""" + buf = _FakeBuffer() + + async def _bump_weight_mid_rollout(_sample): + # Simulate a sync_weights bump during the rollout. + mgr.set_weight_version(5) + + impl = _FakeImpl(record="r0", on_run=_bump_weight_mid_rollout) + mgr = _make_manager(buf, impl) + mgr.set_weight_version(3) + + _run(mgr.generate_and_push({"prompt": "p"})) + + # reserve happened before run_rollout → captured weight 3. + assert buf.reserve_calls == [3] + # commit's start is the same dispatch-time value; end reflects the post-rollout weight. + _, _, start_v, end_v = buf.commit_calls[0] + assert start_v == 3 + assert end_v == 5 + + def test_no_weight_change_means_start_equals_end(self): + buf = _FakeBuffer() + impl = _FakeImpl(record="r0") + mgr = _make_manager(buf, impl) + mgr.set_weight_version(7) + + _run(mgr.generate_and_push({"prompt": "p"})) + + _, _, start_v, end_v = buf.commit_calls[0] + assert start_v == 7 + assert end_v == 7 + + def test_concurrent_dispatch_preserves_reserve_order(self): + """Two concurrent generate_and_push calls must reserve before either commits. + + The contract: reserve order == dispatch order, even if rollouts finish + out of order. Slot order in the buffer reflects the order reserve was + called (not the order run_rollout completed). + """ + buf = _FakeBuffer() + + # First call's rollout blocks until second call has reserved. + first_reserved = asyncio.Event() + second_reserved = asyncio.Event() + + async def _first_run(_sample): + first_reserved.set() + await second_reserved.wait() + + async def _second_run(_sample): + # Second is dispatched only after first reserves, so by the time + # second's reserve fires, slots[0] == first's gid. + second_reserved.set() + + first_impl = _FakeImpl(record="r0", on_run=_first_run) + second_impl = _FakeImpl(record="r1", on_run=_second_run) + + first_mgr = _make_manager(buf, first_impl) + # Share buffer across two managers (mimics two dispatches from one pump). + second_mgr = object.__new__(RolloutManager) + second_mgr._impl = second_impl + second_mgr._tokenizer = None + second_mgr._num_generations_per_prompt = 1 + second_mgr._tq_buffer = buf + second_mgr._weight_version = 0 + + async def _drive(): + t1 = asyncio.create_task(first_mgr.generate_and_push({"prompt": "p1"})) + # Wait until first has reserved before kicking off second so the + # reserve ordering is deterministic. + await first_reserved.wait() + t2 = asyncio.create_task(second_mgr.generate_and_push({"prompt": "p2"})) + await asyncio.gather(t1, t2) + + _run(_drive()) + + # Slots in buffer == reserve order. + first_gid, second_gid = buf._slots + # Commit recorded both, in either order, but each maps to its own gid. + commit_gids = [c[0] for c in buf.commit_calls] + assert set(commit_gids) == {first_gid, second_gid} + assert buf.reserve_calls == [0, 0] + + def test_requires_tq_buffer(self): + mgr = _make_manager(_FakeBuffer(), _FakeImpl()) + mgr._tq_buffer = None + with pytest.raises(AssertionError, match="tq_buffer"): + _run(mgr.generate_and_push({"prompt": "p"})) + + +# --------------------------------------------------------------------------- +# Tests for RolloutManager +# --------------------------------------------------------------------------- + + +def test_rollout_manager_raises_without_impl_params(): + """RolloutManager raises AssertionError when required params are missing.""" + common = { + "tokenizer": None, + "env_handles": {}, + "num_generations_per_prompt": 1, + "max_seq_len": 1, + } + + with pytest.raises(AssertionError, match="num_generations_per_prompt must be >= 1"): + updated_common = common.copy() + updated_common["num_generations_per_prompt"] = 0 + RolloutManager(**updated_common, use_nemo_gym=False) + + with pytest.raises(AssertionError, match="policy_generation is required"): + RolloutManager(**common, use_nemo_gym=False) + + with pytest.raises(AssertionError, match="generation_config is required"): + RolloutManager(**common, use_nemo_gym=True) + + +# --------------------------------------------------------------------------- +# Tests for AsyncRolloutManager (native async path) +# --------------------------------------------------------------------------- + + +@pytest.fixture(scope="function") +def single_multi_step_calculator_input_sample(rollout_tokenizer): # noqa: F811 + """Returns a single DatumSpec prompt dict (problem 0) for AsyncRolloutManager tests.""" + problem_text = "(5 + 3) * 2" + expected_answer = 16.0 + max_steps = 5 + + tool_instructions = ( + "You have a calculator tool. To use it, respond with:\n" + "'[operand1, operand2, operation_name]'\n" + "The valid 'operation_name' values are exactly: 'sum', 'diff', 'prod', 'div'.\n" + "Example: [5, 3, sum]\n" + "You will receive the result of your calculation as ...\n" + "Use this result to make the next calculation if needed.\n" + "IMPORTANT: Only perform one calculation step (one tool call) before waiting for a result and making a new tool call.\n" + "IMPORTANT: Do not perform any other calculations or operations aside from the tool call and result. Doing so will result in failure.\n" + "To give the final answer, just output the number. numbers inside of don't count, so output just the final number yourself outside of this.\n" + "Example full output: [2, 4, sum]\n6.0\n[6, 6, diff]\n0.0 0\n(note how you have to output the final 0 outside of the tags)" + "------\n" + f"Solve: {problem_text}" + ) + + initial_prompt_content = rollout_tokenizer.apply_chat_template( + [{"role": "user", "content": tool_instructions}], + tokenize=False, + add_system_prompt=False, + add_generation_prompt=True, + add_special_tokens=False, + ) + tokenized_prompt = rollout_tokenizer( + initial_prompt_content, return_tensors="pt", add_special_tokens=False + )["input_ids"][0] + message_log = [ + { + "role": "user", + "content": initial_prompt_content, + "token_ids": tokenized_prompt, + } + ] + metadata = MultiStepCalcMetadata( + problem=problem_text, + expected_final_answer=expected_answer, + max_steps=max_steps, + current_step=0, + ) + return { + "message_log": message_log, + "extra_env_info": metadata, + "task_name": "multi_step_calculator_game", + "stop_strings": [""], + "idx": 0, + } + + +@pytest.mark.vllm +def test_async_rollout_manager( + multi_step_setup_vllm_async, # noqa: F811 + single_multi_step_calculator_input_sample, +): + """Standalone test for AsyncRolloutManager. + + Given 1 prompt with num_generations_per_prompt=N, asserts: + - output is a PromptGroupRecord with N Completion objects + - each Completion has a reward (float) and a non-empty message_log + - rollout_metrics has the expected keys with correct types + - completions hold independent (not aliased) message_log objects + """ + vllm_generation, tokenizer, env_handles, _, _ = multi_step_setup_vllm_async + input_sample = single_multi_step_calculator_input_sample + num_generations = 2 + max_seq_len = 1024 + max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 + + manager = RolloutManager( + use_nemo_gym=False, + tokenizer=tokenizer, + env_handles=env_handles, + num_generations_per_prompt=num_generations, + max_seq_len=max_seq_len, + max_rollout_turns=max_rollout_turns, + policy_generation=vllm_generation, + ) + + vllm_generation.prepare_for_generation() + record = asyncio.run(manager.run_rollout(input_sample)) + vllm_generation.finish_generation() + + assert isinstance(record, PromptGroupRecord) + assert len(record.completions) == num_generations, ( + f"Expected {num_generations} completions, got {len(record.completions)}" + ) + assert record.prompt_idx == input_sample["idx"] + + for i, completion in enumerate(record.completions): + assert isinstance(completion, Completion) + + # 1. message_log length + assert len(completion.message_log) >= 4, ( + f"Completion {i}: expected >= 4 messages, got {len(completion.message_log)}" + ) + + # 2. last assistant content + last_assistant = next( + (m for m in reversed(completion.message_log) if m["role"] == "assistant"), + None, + ) + assert last_assistant is not None, f"Completion {i}: no assistant message found" + assert last_assistant["content"].strip() == "16", ( + f"Completion {i}: last assistant content {last_assistant['content']!r} != '16'" + ) + + # 3. reward + assert completion.reward == 1.0, ( + f"Completion {i}: reward {completion.reward} != 1.0" + ) + + # completions must be independent objects + assert record.completions[0].message_log is not record.completions[1].message_log + + +@pytest.mark.vllm +def test_async_rollout_manager_truncation( + multi_step_setup_vllm_async, # noqa: F811 + single_multi_step_calculator_input_sample, +): + """Small max_seq_len forces truncation and truncation_rate=1.0.""" + vllm_generation, tokenizer, env_handles, _, _ = multi_step_setup_vllm_async + input_sample = single_multi_step_calculator_input_sample + num_generations = 2 + max_seq_len = 290 + max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 + + manager = RolloutManager( + use_nemo_gym=False, + tokenizer=tokenizer, + env_handles=env_handles, + num_generations_per_prompt=num_generations, + max_seq_len=max_seq_len, + max_rollout_turns=max_rollout_turns, + policy_generation=vllm_generation, + ) + vllm_generation.prepare_for_generation() + record = asyncio.run(manager.run_rollout(input_sample)) + vllm_generation.finish_generation() + + assert len(record.completions) == num_generations + assert all(c.truncated for c in record.completions) + assert record.rollout_metrics["truncation_rate"] == 1.0 + assert record.rollout_metrics["natural_termination_rate"] == 0.0 + + +@pytest.mark.vllm +def test_async_rollout_manager_matches_original( + multi_step_setup_vllm_async, # noqa: F811 + single_multi_step_calculator_input_sample, +): + """Comparison test: AsyncRolloutManager output is structurally equivalent to the original. + + Calls run_async_multi_turn_rollout with a batch of N identical prompts, + then calls AsyncRolloutManager with 1 prompt and N generations. + Asserts that both produce N results with matching message-log depth, rewards, + and rollout_metrics numeric values. + + TODO: remove this test together with run_async_multi_turn_rollout when the legacy path is deleted. + """ + vllm_generation, tokenizer, env_handles, _, _ = multi_step_setup_vllm_async + input_sample = single_multi_step_calculator_input_sample + num_generations = 2 + max_seq_len = 1024 + max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 + + # Build a batch of N identical prompts for the original function + batch = BatchedDataDict( + { + "message_log": [ + deepcopy(input_sample["message_log"]) for _ in range(num_generations) + ], + "extra_env_info": [ + deepcopy(input_sample["extra_env_info"]) for _ in range(num_generations) + ], + "task_name": [input_sample["task_name"]] * num_generations, + "stop_strings": [input_sample["stop_strings"]] * num_generations, + "idx": list(range(num_generations)), + "loss_multiplier": [1.0] * num_generations, + } + ) + + vllm_generation.prepare_for_generation() + original_batch, original_metrics = run_async_multi_turn_rollout( + policy_generation=vllm_generation, + input_batch=batch, + tokenizer=tokenizer, + task_to_env=env_handles, + max_seq_len=max_seq_len, + max_rollout_turns=max_rollout_turns, + ) + + manager = RolloutManager( + use_nemo_gym=False, + tokenizer=tokenizer, + env_handles=env_handles, + num_generations_per_prompt=num_generations, + max_seq_len=max_seq_len, + max_rollout_turns=max_rollout_turns, + policy_generation=vllm_generation, + ) + record = asyncio.run(manager.run_rollout(input_sample)) + vllm_generation.finish_generation() + + # Both should produce N results + assert len(original_batch["message_log"]) == num_generations + assert len(record.completions) == num_generations + + for i in range(num_generations): + orig_msg_log = original_batch["message_log"][i] + new_msg_log = record.completions[i].message_log + + # 1. message_log length matches + assert len(orig_msg_log) == len(new_msg_log), ( + f"Completion {i}: message_log length {len(new_msg_log)} != original {len(orig_msg_log)}" + ) + + # 2. last assistant content matches + def _last_assistant_content(msg_log): + for m in reversed(msg_log): + if m["role"] == "assistant": + return m.get("content", "") + return "" + + orig_last = _last_assistant_content(orig_msg_log) + new_last = _last_assistant_content(new_msg_log) + assert orig_last == new_last, ( + f"Completion {i}: last assistant content mismatch\n" + f" original: {orig_last!r}\n" + f" manager: {new_last!r}" + ) + + # 3. reward matches + orig_reward = original_batch["total_reward"][i].item() + new_reward = record.completions[i].reward + assert orig_reward == new_reward, ( + f"Completion {i}: reward mismatch — original {orig_reward}, manager {new_reward}" + ) + + # 4. rollout_metrics numeric values match (timing and histogram fields are excluded). + # The new impl emits slash-style keys (X/mean, X/max, X/min) via _calculate_single_metric; + # translate the legacy prefix-style keys before comparing. + def _translate_legacy_key(key: str) -> str: + if key == "avg_turns_per_sample": + return "turns_per_sample/mean" + if key == "max_turns_reached_rate": + return key + for prefix, suffix in (("mean_", "/mean"), ("max_", "/max"), ("min_", "/min")): + if key.startswith(prefix): + return f"{key[len(prefix) :]}{suffix}" + return key + + new_metrics = record.rollout_metrics + for key in original_metrics.keys(): + if key.startswith("timing/") or key.startswith("histogram/"): + continue + + new_key = _translate_legacy_key(key) + assert new_key in new_metrics, ( + f"rollout_metrics[{new_key!r}] missing from manager" + ) + + orig_val = original_metrics[key] + new_val = new_metrics[new_key] + + assert type(orig_val) == type(new_val), ( + f"rollout_metrics[{key!r}] type mismatch: {type(orig_val)} != {type(new_val)}" + ) + if not isinstance(orig_val, (bool, int, float)): + continue + + assert orig_val == pytest.approx(new_val), ( + f"rollout_metrics[{key!r}] mismatch — original {orig_val}, manager {new_val}" + ) + + +# --------------------------------------------------------------------------- +# Tests for AsyncNemoGymRolloutManager +# --------------------------------------------------------------------------- + + +@pytest.mark.nemo_gym +def test_async_nemo_gym_rollout_manager( + nemo_gym, # noqa: F811 + nemo_gym_vllm_generation, # noqa: F811 + nemo_gym_sanity_test_data, # noqa: F811 + nemo_gym_tokenizer, # noqa: F811 +): + """Standalone test for AsyncNemoGymRolloutManager. + + Given 1 prompt with num_generations_per_prompt=N, asserts: + - output is a PromptGroupRecord with N Completion objects + - each Completion has a reward (float) and a non-empty message_log + - completions hold independent message_log objects + + If the result here does not match, please check the following: + 1. Test data changed: re-run test_nemo_gym_sanity (tests/unit/environments/test_nemo_gym.py) + and use _write_actual_test_data output to refresh test_nemo_gym_sanity.json. + 2. Logic changed: inspect recent changes to AsyncNemoGymRolloutManager or the gym env. + """ + with tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False) as f: + for data in nemo_gym_sanity_test_data["input"]: + f.write(json.dumps(data) + "\n") + data_path = f.name + + dataset = NemoGymDataset(data_path) + examples = [ + nemo_gym_data_processor(dataset.dataset[idx], None, None, None, idx) + for idx in range(len(dataset.dataset)) + ] + input_batch: BatchedDataDict[DatumSpec] = rl_collate_fn(examples) + + # Use only the first prompt + single_prompt = { + "message_log": input_batch["message_log"][0], + "extra_env_info": input_batch["extra_env_info"][0], + "task_name": "nemo_gym", + "idx": 0, + "loss_multiplier": float(input_batch["loss_multiplier"][0]), + } + num_generations = 2 + + manager = RolloutManager( + use_nemo_gym=True, + tokenizer=nemo_gym_tokenizer, + env_handles={"nemo_gym": nemo_gym}, + num_generations_per_prompt=num_generations, + max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], + generation_config=nemo_gym_vllm_generation.cfg, + ) + record = asyncio.run(manager.run_rollout(single_prompt)) + + assert isinstance(record, PromptGroupRecord) + assert len(record.completions) == num_generations, ( + f"Expected {num_generations} completions, got {len(record.completions)}" + ) + assert record.prompt_idx == 0 + + for i, completion in enumerate(record.completions): + assert isinstance(completion, Completion) + + # 1. message_log length + assert len(completion.message_log) == 2, ( + f"Completion {i}: expected 2 messages, got {len(completion.message_log)}" + ) + + # 2. last assistant token_ids + last_assistant = next( + (m for m in reversed(completion.message_log) if m["role"] == "assistant"), + None, + ) + assert last_assistant is not None, f"Completion {i}: no assistant message found" + assert torch.equal( + last_assistant["token_ids"], + torch.tensor([151667, 198, 32313, 11, 1077]), + ), ( + f"Completion {i}: last assistant token_ids {last_assistant['token_ids'].tolist()} " + f"!= [151667, 198, 32313, 11, 1077]" + ) + + # 3. reward + assert completion.reward == 0.0, ( + f"Completion {i}: reward {completion.reward} != 0.0" + ) + + # completions must be independent objects + assert record.completions[0].message_log is not record.completions[1].message_log + + +@pytest.mark.nemo_gym +def test_async_nemo_gym_rollout_manager_matches_original( + nemo_gym, # noqa: F811 + nemo_gym_vllm_generation, # noqa: F811 + nemo_gym_sanity_test_data, # noqa: F811 + nemo_gym_tokenizer, # noqa: F811 +): + """Comparison test: AsyncNemoGymRolloutManager output is structurally equivalent to the original. + + Calls run_async_nemo_gym_rollout with a batch of N identical rows, + then calls AsyncNemoGymRolloutManager with 1 prompt, N generations. + Asserts that both produce N results and rewards are in the same numeric domain. + + TODO: remove this test together with run_async_nemo_gym_rollout when the legacy path is deleted. + """ + with tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False) as f: + for data in nemo_gym_sanity_test_data["input"]: + f.write(json.dumps(data) + "\n") + data_path = f.name + + dataset = NemoGymDataset(data_path) + examples = [ + nemo_gym_data_processor(dataset.dataset[idx], None, None, None, idx) + for idx in range(len(dataset.dataset)) + ] + input_batch: BatchedDataDict[DatumSpec] = rl_collate_fn(examples) + + num_generations = 2 + single_prompt = { + "message_log": input_batch["message_log"][0], + "extra_env_info": input_batch["extra_env_info"][0], + "task_name": "nemo_gym", + "idx": 0, + "loss_multiplier": float(input_batch["loss_multiplier"][0]), + } + + # Build a batch of N identical rows for the original function + repeated_batch = BatchedDataDict( + { + "message_log": [ + deepcopy(input_batch["message_log"][0]) for _ in range(num_generations) + ], + "extra_env_info": [ + deepcopy(input_batch["extra_env_info"][0]) + for _ in range(num_generations) + ], + "loss_multiplier": input_batch["loss_multiplier"][0:1].repeat( + num_generations + ), + "idx": list(range(num_generations)), + "task_name": ["nemo_gym"] * num_generations, + } + ) + + original_result = run_async_nemo_gym_rollout( + policy_generation=nemo_gym_vllm_generation, + input_batch=repeated_batch, + tokenizer=nemo_gym_tokenizer, + task_to_env={"nemo_gym": nemo_gym}, + generation_config=nemo_gym_vllm_generation.cfg, + max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], + max_rollout_turns=None, + ) + + manager = RolloutManager( + use_nemo_gym=True, + tokenizer=nemo_gym_tokenizer, + env_handles={"nemo_gym": nemo_gym}, + num_generations_per_prompt=num_generations, + max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], + generation_config=nemo_gym_vllm_generation.cfg, + ) + record = asyncio.run(manager.run_rollout(single_prompt)) + + # Both should produce N completions + assert len(original_result.final_batch["message_log"]) == num_generations + assert len(record.completions) == num_generations + + for i in range(num_generations): + orig_msg_log = original_result.final_batch["message_log"][i] + new_msg_log = record.completions[i].message_log + + # 1. message_log length matches + assert len(orig_msg_log) == len(new_msg_log), ( + f"Completion {i}: message_log length {len(new_msg_log)} != original {len(orig_msg_log)}" + ) + + # 2. last assistant token_ids match + def _last_assistant_token_ids(msg_log): + for m in reversed(msg_log): + if m["role"] == "assistant": + return m.get("token_ids") + return None + + orig_token_ids = _last_assistant_token_ids(orig_msg_log) + new_token_ids = _last_assistant_token_ids(new_msg_log) + assert orig_token_ids is not None, ( + f"Completion {i}: no assistant message in original" + ) + assert new_token_ids is not None, ( + f"Completion {i}: no assistant message in manager" + ) + assert torch.equal(orig_token_ids, new_token_ids), ( + f"Completion {i}: last assistant token_ids mismatch\n" + f" original: {orig_token_ids.tolist()}\n" + f" manager: {new_token_ids.tolist()}" + ) + + # 3. reward matches + orig_reward = original_result.final_batch["total_reward"][i].item() + new_reward = record.completions[i].reward + assert orig_reward == new_reward, ( + f"Completion {i}: reward mismatch — original {orig_reward}, manager {new_reward}" + ) + + # 4. rollout_metrics numeric values match (timing and Table fields are excluded) + orig_metrics = original_result.rollout_metrics + new_metrics = record.rollout_metrics + for key in orig_metrics.keys(): + # Skip timing and full_result fields + if key.startswith("timing/") or key.endswith("/full_result"): + continue + + # Check that the key is present in the new metrics + assert key in new_metrics, f"rollout_metrics[{key!r}] missing from manager" + + orig_val = orig_metrics[key] + new_val = new_metrics[key] + + # Skip non-numeric fields + assert type(orig_val) == type(new_val), ( + f"rollout_metrics[{key!r}] type mismatch: {type(orig_val)} != {type(new_val)}" + ) + if not isinstance(orig_val, (bool, int, float)): + continue + + # Check equal + assert orig_val == pytest.approx(new_val), ( + f"rollout_metrics[{key!r}] mismatch — original {orig_val}, manager {new_val}" + ) diff --git a/tests/unit/experience/test_rollouts.py b/tests/unit/experience/test_rollouts.py index c604f2f1d41..95fb940cbcc 100644 --- a/tests/unit/experience/test_rollouts.py +++ b/tests/unit/experience/test_rollouts.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import asyncio import gc import json import tempfile @@ -37,8 +36,6 @@ SlidingPuzzleGameLogic, SlidingPuzzleMetadata, ) -from nemo_rl.experience.interfaces import Completion, PromptGroupRecord -from nemo_rl.experience.rollout_manager import RolloutManager from nemo_rl.experience.rollouts import ( _calculate_single_metric, generate_responses_async, @@ -1033,550 +1030,3 @@ def _standardize(d: dict) -> dict: 1. In nemo_rl/experience/rollouts.py::run_async_nemo_gym_rollout, the sampling params are passed appropriately 2. In nemo_rl/models/generation/vllm/vllm_worker_async.py::VllmAsyncGenerationWorker::_setup_vllm_server::create_chat_completion, the sampling params (like top_k) are set as appropriate """ - - -# --------------------------------------------------------------------------- -# Tests for RolloutManager -# --------------------------------------------------------------------------- - - -def test_rollout_manager_raises_without_impl_params(): - """RolloutManager raises AssertionError when required params are missing.""" - common = { - "tokenizer": None, - "env_handles": {}, - "num_generations_per_prompt": 1, - "max_seq_len": 1, - } - - with pytest.raises(AssertionError, match="num_generations_per_prompt must be >= 1"): - updated_common = common.copy() - updated_common["num_generations_per_prompt"] = 0 - RolloutManager(**updated_common, use_nemo_gym=False) - - with pytest.raises(AssertionError, match="policy_generation is required"): - RolloutManager(**common, use_nemo_gym=False) - - with pytest.raises(AssertionError, match="generation_config is required"): - RolloutManager(**common, use_nemo_gym=True) - - -# --------------------------------------------------------------------------- -# Tests for AsyncRolloutManager (native async path) -# --------------------------------------------------------------------------- - - -@pytest.fixture(scope="function") -def single_multi_step_calculator_input_sample(rollout_tokenizer): - """Returns a single DatumSpec prompt dict (problem 0) for AsyncRolloutManager tests.""" - problem_text = "(5 + 3) * 2" - expected_answer = 16.0 - max_steps = 5 - - tool_instructions = ( - "You have a calculator tool. To use it, respond with:\n" - "'[operand1, operand2, operation_name]'\n" - "The valid 'operation_name' values are exactly: 'sum', 'diff', 'prod', 'div'.\n" - "Example: [5, 3, sum]\n" - "You will receive the result of your calculation as ...\n" - "Use this result to make the next calculation if needed.\n" - "IMPORTANT: Only perform one calculation step (one tool call) before waiting for a result and making a new tool call.\n" - "IMPORTANT: Do not perform any other calculations or operations aside from the tool call and result. Doing so will result in failure.\n" - "To give the final answer, just output the number. numbers inside of don't count, so output just the final number yourself outside of this.\n" - "Example full output: [2, 4, sum]\n6.0\n[6, 6, diff]\n0.0 0\n(note how you have to output the final 0 outside of the tags)" - "------\n" - f"Solve: {problem_text}" - ) - - initial_prompt_content = rollout_tokenizer.apply_chat_template( - [{"role": "user", "content": tool_instructions}], - tokenize=False, - add_system_prompt=False, - add_generation_prompt=True, - add_special_tokens=False, - ) - tokenized_prompt = rollout_tokenizer( - initial_prompt_content, return_tensors="pt", add_special_tokens=False - )["input_ids"][0] - message_log = [ - { - "role": "user", - "content": initial_prompt_content, - "token_ids": tokenized_prompt, - } - ] - metadata = MultiStepCalcMetadata( - problem=problem_text, - expected_final_answer=expected_answer, - max_steps=max_steps, - current_step=0, - ) - return { - "message_log": message_log, - "extra_env_info": metadata, - "task_name": "multi_step_calculator_game", - "stop_strings": [""], - "idx": 0, - } - - -@pytest.mark.vllm -def test_async_rollout_manager( - multi_step_setup_vllm_async, - single_multi_step_calculator_input_sample, -): - """Standalone test for AsyncRolloutManager. - - Given 1 prompt with num_generations_per_prompt=N, asserts: - - output is a PromptGroupRecord with N Completion objects - - each Completion has a reward (float) and a non-empty message_log - - rollout_metrics has the expected keys with correct types - - completions hold independent (not aliased) message_log objects - """ - vllm_generation, rollout_tokenizer, env_handles, _, _ = multi_step_setup_vllm_async - input_sample = single_multi_step_calculator_input_sample - num_generations = 2 - max_seq_len = 1024 - max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 - - manager = RolloutManager( - use_nemo_gym=False, - tokenizer=rollout_tokenizer, - env_handles=env_handles, - num_generations_per_prompt=num_generations, - max_seq_len=max_seq_len, - max_rollout_turns=max_rollout_turns, - policy_generation=vllm_generation, - ) - - vllm_generation.prepare_for_generation() - record = asyncio.run(manager.run_rollout(input_sample)) - vllm_generation.finish_generation() - - assert isinstance(record, PromptGroupRecord) - assert len(record.completions) == num_generations, ( - f"Expected {num_generations} completions, got {len(record.completions)}" - ) - assert record.prompt_idx == input_sample["idx"] - - for i, completion in enumerate(record.completions): - assert isinstance(completion, Completion) - - # 1. message_log length - assert len(completion.message_log) >= 4, ( - f"Completion {i}: expected >= 4 messages, got {len(completion.message_log)}" - ) - - # 2. last assistant content - last_assistant = next( - (m for m in reversed(completion.message_log) if m["role"] == "assistant"), - None, - ) - assert last_assistant is not None, f"Completion {i}: no assistant message found" - assert last_assistant["content"].strip() == "16", ( - f"Completion {i}: last assistant content {last_assistant['content']!r} != '16'" - ) - - # 3. reward - assert completion.reward == 1.0, ( - f"Completion {i}: reward {completion.reward} != 1.0" - ) - - # completions must be independent objects - assert record.completions[0].message_log is not record.completions[1].message_log - - -@pytest.mark.vllm -def test_async_rollout_manager_truncation( - multi_step_setup_vllm_async, - single_multi_step_calculator_input_sample, -): - """Small max_seq_len forces truncation and truncation_rate=1.0.""" - vllm_generation, rollout_tokenizer, task_to_env, _, _ = multi_step_setup_vllm_async - input_sample = single_multi_step_calculator_input_sample - num_generations = 2 - max_seq_len = 290 - max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 - - manager = RolloutManager( - use_nemo_gym=False, - tokenizer=rollout_tokenizer, - task_to_env=task_to_env, - num_generations_per_prompt=num_generations, - max_seq_len=max_seq_len, - max_rollout_turns=max_rollout_turns, - policy_generation=vllm_generation, - ) - vllm_generation.prepare_for_generation() - record = asyncio.run(manager.run_rollout(input_sample)) - vllm_generation.finish_generation() - - assert len(record.completions) == num_generations - assert all(c.truncated for c in record.completions) - assert record.rollout_metrics["truncation_rate"] == 1.0 - assert record.rollout_metrics["natural_termination_rate"] == 0.0 - - -@pytest.mark.vllm -def test_async_rollout_manager_matches_original( - multi_step_setup_vllm_async, - single_multi_step_calculator_input_sample, -): - """Comparison test: AsyncRolloutManager output is structurally equivalent to the original. - - Calls run_async_multi_turn_rollout with a batch of N identical prompts, - then calls AsyncRolloutManager with 1 prompt and N generations. - Asserts that both produce N results with matching message-log depth, rewards, - and rollout_metrics numeric values. - - TODO: remove this test together with run_async_multi_turn_rollout when the legacy path is deleted. - """ - vllm_generation, rollout_tokenizer, env_handles, _, _ = multi_step_setup_vllm_async - input_sample = single_multi_step_calculator_input_sample - num_generations = 2 - max_seq_len = 1024 - max_rollout_turns = input_sample["extra_env_info"]["max_steps"] + 1 - - # Build a batch of N identical prompts for the original function - batch = BatchedDataDict( - { - "message_log": [ - deepcopy(input_sample["message_log"]) for _ in range(num_generations) - ], - "extra_env_info": [ - deepcopy(input_sample["extra_env_info"]) for _ in range(num_generations) - ], - "task_name": [input_sample["task_name"]] * num_generations, - "stop_strings": [input_sample["stop_strings"]] * num_generations, - "idx": list(range(num_generations)), - "loss_multiplier": [1.0] * num_generations, - } - ) - - vllm_generation.prepare_for_generation() - original_batch, original_metrics = run_async_multi_turn_rollout( - policy_generation=vllm_generation, - input_batch=batch, - tokenizer=rollout_tokenizer, - task_to_env=env_handles, - max_seq_len=max_seq_len, - max_rollout_turns=max_rollout_turns, - ) - - manager = RolloutManager( - use_nemo_gym=False, - tokenizer=rollout_tokenizer, - env_handles=env_handles, - num_generations_per_prompt=num_generations, - max_seq_len=max_seq_len, - max_rollout_turns=max_rollout_turns, - policy_generation=vllm_generation, - ) - record = asyncio.run(manager.run_rollout(input_sample)) - vllm_generation.finish_generation() - - # Both should produce N results - assert len(original_batch["message_log"]) == num_generations - assert len(record.completions) == num_generations - - for i in range(num_generations): - orig_msg_log = original_batch["message_log"][i] - new_msg_log = record.completions[i].message_log - - # 1. message_log length matches - assert len(orig_msg_log) == len(new_msg_log), ( - f"Completion {i}: message_log length {len(new_msg_log)} != original {len(orig_msg_log)}" - ) - - # 2. last assistant content matches - def _last_assistant_content(msg_log): - for m in reversed(msg_log): - if m["role"] == "assistant": - return m.get("content", "") - return "" - - orig_last = _last_assistant_content(orig_msg_log) - new_last = _last_assistant_content(new_msg_log) - assert orig_last == new_last, ( - f"Completion {i}: last assistant content mismatch\n" - f" original: {orig_last!r}\n" - f" manager: {new_last!r}" - ) - - # 3. reward matches - orig_reward = original_batch["total_reward"][i].item() - new_reward = record.completions[i].reward - assert orig_reward == new_reward, ( - f"Completion {i}: reward mismatch — original {orig_reward}, manager {new_reward}" - ) - - # 4. rollout_metrics numeric values match (timing and histogram fields are excluded). - # The new impl emits slash-style keys (X/mean, X/max, X/min) via _calculate_single_metric; - # translate the legacy prefix-style keys before comparing. - def _translate_legacy_key(key: str) -> str: - if key == "avg_turns_per_sample": - return "turns_per_sample/mean" - if key == "max_turns_reached_rate": - return key - for prefix, suffix in (("mean_", "/mean"), ("max_", "/max"), ("min_", "/min")): - if key.startswith(prefix): - return f"{key[len(prefix) :]}{suffix}" - return key - - new_metrics = record.rollout_metrics - for key in original_metrics.keys(): - if key.startswith("timing/") or key.startswith("histogram/"): - continue - - new_key = _translate_legacy_key(key) - assert new_key in new_metrics, ( - f"rollout_metrics[{new_key!r}] missing from manager" - ) - - orig_val = original_metrics[key] - new_val = new_metrics[new_key] - - assert type(orig_val) == type(new_val), ( - f"rollout_metrics[{key!r}] type mismatch: {type(orig_val)} != {type(new_val)}" - ) - if not isinstance(orig_val, (bool, int, float)): - continue - - assert orig_val == pytest.approx(new_val), ( - f"rollout_metrics[{key!r}] mismatch — original {orig_val}, manager {new_val}" - ) - - -# --------------------------------------------------------------------------- -# Tests for AsyncNemoGymRolloutManager -# --------------------------------------------------------------------------- - - -@pytest.mark.nemo_gym -def test_async_nemo_gym_rollout_manager( - nemo_gym, # noqa: F811 - nemo_gym_vllm_generation, # noqa: F811 - nemo_gym_sanity_test_data, # noqa: F811 - nemo_gym_tokenizer, # noqa: F811 -): - """Standalone test for AsyncNemoGymRolloutManager. - - Given 1 prompt with num_generations_per_prompt=N, asserts: - - output is a PromptGroupRecord with N Completion objects - - each Completion has a reward (float) and a non-empty message_log - - completions hold independent message_log objects - - If the result here does not match, please check the following: - 1. Test data changed: re-run test_nemo_gym_sanity (tests/unit/environments/test_nemo_gym.py) - and use _write_actual_test_data output to refresh test_nemo_gym_sanity.json. - 2. Logic changed: inspect recent changes to AsyncNemoGymRolloutManager or the gym env. - """ - with tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False) as f: - for data in nemo_gym_sanity_test_data["input"]: - f.write(json.dumps(data) + "\n") - data_path = f.name - - dataset = NemoGymDataset(data_path) - examples = [ - nemo_gym_data_processor(dataset.dataset[idx], None, None, None, idx) - for idx in range(len(dataset.dataset)) - ] - input_batch: BatchedDataDict[DatumSpec] = rl_collate_fn(examples) - - # Use only the first prompt - single_prompt = { - "message_log": input_batch["message_log"][0], - "extra_env_info": input_batch["extra_env_info"][0], - "task_name": "nemo_gym", - "idx": 0, - "loss_multiplier": float(input_batch["loss_multiplier"][0]), - } - num_generations = 2 - - manager = RolloutManager( - use_nemo_gym=True, - tokenizer=nemo_gym_tokenizer, - env_handles={"nemo_gym": nemo_gym}, - num_generations_per_prompt=num_generations, - max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], - generation_config=nemo_gym_vllm_generation.cfg, - ) - record = asyncio.run(manager.run_rollout(single_prompt)) - - assert isinstance(record, PromptGroupRecord) - assert len(record.completions) == num_generations, ( - f"Expected {num_generations} completions, got {len(record.completions)}" - ) - assert record.prompt_idx == 0 - - for i, completion in enumerate(record.completions): - assert isinstance(completion, Completion) - - # 1. message_log length - assert len(completion.message_log) == 2, ( - f"Completion {i}: expected 2 messages, got {len(completion.message_log)}" - ) - - # 2. last assistant token_ids - last_assistant = next( - (m for m in reversed(completion.message_log) if m["role"] == "assistant"), - None, - ) - assert last_assistant is not None, f"Completion {i}: no assistant message found" - assert torch.equal( - last_assistant["token_ids"], - torch.tensor([151667, 198, 32313, 11, 1077]), - ), ( - f"Completion {i}: last assistant token_ids {last_assistant['token_ids'].tolist()} " - f"!= [151667, 198, 32313, 11, 1077]" - ) - - # 3. reward - assert completion.reward == 0.0, ( - f"Completion {i}: reward {completion.reward} != 0.0" - ) - - # completions must be independent objects - assert record.completions[0].message_log is not record.completions[1].message_log - - -@pytest.mark.nemo_gym -def test_async_nemo_gym_rollout_manager_matches_original( - nemo_gym, # noqa: F811 - nemo_gym_vllm_generation, # noqa: F811 - nemo_gym_sanity_test_data, # noqa: F811 - nemo_gym_tokenizer, # noqa: F811 -): - """Comparison test: AsyncNemoGymRolloutManager output is structurally equivalent to the original. - - Calls run_async_nemo_gym_rollout with a batch of N identical rows, - then calls AsyncNemoGymRolloutManager with 1 prompt, N generations. - Asserts that both produce N results and rewards are in the same numeric domain. - - TODO: remove this test together with run_async_nemo_gym_rollout when the legacy path is deleted. - """ - with tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False) as f: - for data in nemo_gym_sanity_test_data["input"]: - f.write(json.dumps(data) + "\n") - data_path = f.name - - dataset = NemoGymDataset(data_path) - examples = [ - nemo_gym_data_processor(dataset.dataset[idx], None, None, None, idx) - for idx in range(len(dataset.dataset)) - ] - input_batch: BatchedDataDict[DatumSpec] = rl_collate_fn(examples) - - num_generations = 2 - single_prompt = { - "message_log": input_batch["message_log"][0], - "extra_env_info": input_batch["extra_env_info"][0], - "task_name": "nemo_gym", - "idx": 0, - "loss_multiplier": float(input_batch["loss_multiplier"][0]), - } - - # Build a batch of N identical rows for the original function - repeated_batch = BatchedDataDict( - { - "message_log": [ - deepcopy(input_batch["message_log"][0]) for _ in range(num_generations) - ], - "extra_env_info": [ - deepcopy(input_batch["extra_env_info"][0]) - for _ in range(num_generations) - ], - "loss_multiplier": input_batch["loss_multiplier"][0:1].repeat( - num_generations - ), - "idx": list(range(num_generations)), - "task_name": ["nemo_gym"] * num_generations, - } - ) - - original_result = run_async_nemo_gym_rollout( - policy_generation=nemo_gym_vllm_generation, - input_batch=repeated_batch, - tokenizer=nemo_gym_tokenizer, - task_to_env={"nemo_gym": nemo_gym}, - generation_config=nemo_gym_vllm_generation.cfg, - max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], - max_rollout_turns=None, - ) - - manager = RolloutManager( - use_nemo_gym=True, - tokenizer=nemo_gym_tokenizer, - env_handles={"nemo_gym": nemo_gym}, - num_generations_per_prompt=num_generations, - max_seq_len=nemo_gym_vllm_generation.cfg["vllm_cfg"]["max_model_len"], - generation_config=nemo_gym_vllm_generation.cfg, - ) - record = asyncio.run(manager.run_rollout(single_prompt)) - - # Both should produce N completions - assert len(original_result.final_batch["message_log"]) == num_generations - assert len(record.completions) == num_generations - - for i in range(num_generations): - orig_msg_log = original_result.final_batch["message_log"][i] - new_msg_log = record.completions[i].message_log - - # 1. message_log length matches - assert len(orig_msg_log) == len(new_msg_log), ( - f"Completion {i}: message_log length {len(new_msg_log)} != original {len(orig_msg_log)}" - ) - - # 2. last assistant token_ids match - def _last_assistant_token_ids(msg_log): - for m in reversed(msg_log): - if m["role"] == "assistant": - return m.get("token_ids") - return None - - orig_token_ids = _last_assistant_token_ids(orig_msg_log) - new_token_ids = _last_assistant_token_ids(new_msg_log) - assert orig_token_ids is not None, ( - f"Completion {i}: no assistant message in original" - ) - assert new_token_ids is not None, ( - f"Completion {i}: no assistant message in manager" - ) - assert torch.equal(orig_token_ids, new_token_ids), ( - f"Completion {i}: last assistant token_ids mismatch\n" - f" original: {orig_token_ids.tolist()}\n" - f" manager: {new_token_ids.tolist()}" - ) - - # 3. reward matches - orig_reward = original_result.final_batch["total_reward"][i].item() - new_reward = record.completions[i].reward - assert orig_reward == new_reward, ( - f"Completion {i}: reward mismatch — original {orig_reward}, manager {new_reward}" - ) - - # 4. rollout_metrics numeric values match (timing and Table fields are excluded) - orig_metrics = original_result.rollout_metrics - new_metrics = record.rollout_metrics - for key in orig_metrics.keys(): - # Skip timing and full_result fields - if key.startswith("timing/") or key.endswith("/full_result"): - continue - - # Check that the key is present in the new metrics - assert key in new_metrics, f"rollout_metrics[{key!r}] missing from manager" - - orig_val = orig_metrics[key] - new_val = new_metrics[key] - - # Skip non-numeric fields - assert type(orig_val) == type(new_val), ( - f"rollout_metrics[{key!r}] type mismatch: {type(orig_val)} != {type(new_val)}" - ) - if not isinstance(orig_val, (bool, int, float)): - continue - - # Check equal - assert orig_val == pytest.approx(new_val), ( - f"rollout_metrics[{key!r}] mismatch — original {orig_val}, manager {new_val}" - ) diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index ff98698daf8..62d13bc1525 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -40,13 +40,15 @@ from nemo_rl.experience.rollout_manager import RolloutManager # Reuse fixtures from the experience tests; same shape as test_async_rollout_manager. +from tests.unit.experience.test_rollout_manager import ( + single_multi_step_calculator_input_sample, # noqa: F401 +) from tests.unit.experience.test_rollouts import ( initial_multi_step_calculator_batch, # noqa: F401 multi_step_calculator_environment, # noqa: F401 multi_step_setup_vllm_async, # noqa: F401 rollout_cluster, # noqa: F401 rollout_tokenizer, # noqa: F401 - single_multi_step_calculator_input_sample, # noqa: F401 ) _PARTITION_ID = "rollout_data" diff --git a/tests/unit/single_controller/test_staleness_sampler.py b/tests/unit/single_controller/test_staleness_sampler.py index 866c83f2d98..d07c07fce4b 100644 --- a/tests/unit/single_controller/test_staleness_sampler.py +++ b/tests/unit/single_controller/test_staleness_sampler.py @@ -29,11 +29,20 @@ class FakeBuffer: def __init__(self, partition_id: str = "rollout_data") -> None: self._partition_id = partition_id - self.meta_list: list[KVBatchMeta] = [] - self.weight_list: list[int] = [] + self.meta_list: list[KVBatchMeta | None] = [] + self.start_weight_list: list[int] = [] + self.end_weight_list: list[int] = [] + self.ready_list: list[bool] = [] self.remove_calls: list[tuple[list[int], bool]] = [] - def add(self, group_id: str, weight: int, group_size: int = 1) -> KVBatchMeta: + def add( + self, + group_id: str, + weight: int, + group_size: int = 1, + ready: bool = True, + end_weight: int | None = None, + ) -> KVBatchMeta: sample_ids = [f"{group_id}_g{i}" for i in range(group_size)] meta = KVBatchMeta( partition_id=self._partition_id, @@ -41,15 +50,19 @@ def add(self, group_id: str, weight: int, group_size: int = 1) -> KVBatchMeta: sample_ids=sample_ids, tags=[{"weight_version": weight, "group_id": group_id}] * group_size, ) - self.meta_list.append(meta) - self.weight_list.append(weight) + self.meta_list.append(meta if ready else None) + self.start_weight_list.append(weight) + self.end_weight_list.append(weight if end_weight is None else end_weight) + self.ready_list.append(ready) return meta async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: self.remove_calls.append((list(idxs), remove_in_dp)) for i in sorted(idxs, reverse=True): del self.meta_list[i] - del self.weight_list[i] + del self.start_weight_list[i] + del self.end_weight_list[i] + del self.ready_list[i] return len(idxs) @@ -186,7 +199,7 @@ def test_select_drops_returned_entries_from_buffer(self): assert first_meta is not None assert first_meta.sample_ids == ["g0_g0"] assert first_num_groups == 1 - assert buf.weight_list == [5, 5] + assert buf.start_weight_list == [5, 5] # remove_in_dp=False; DP rows kept for trainer. assert buf.remove_calls[-1][1] is False @@ -215,7 +228,7 @@ def test_evict_removes_stale_groups(self): dropped = _run(sampler.evict(current_train_weight=5)) assert dropped == 3 - assert buf.weight_list == [4, 5] + assert buf.start_weight_list == [4, 5] # Survivors' sample_ids assert [m.sample_ids[0] for m in buf.meta_list] == ["g2_g0", "g3_g0"] @@ -234,7 +247,7 @@ def test_evict_keeps_future_groups(self): sampler = StalenessSampler(buf, max_staleness_versions=0) assert _run(sampler.evict(current_train_weight=5)) == 0 - assert buf.weight_list == [7] + assert buf.start_weight_list == [7] def test_evict_drops_whole_group(self): buf = FakeBuffer() @@ -246,7 +259,7 @@ def test_evict_drops_whole_group(self): assert dropped == 1 assert buf.remove_calls == [([0], True)] - assert buf.weight_list == [5] + assert buf.start_weight_list == [5] assert [m.sample_ids[0] for m in buf.meta_list] == ["fresh_g0"] @@ -255,3 +268,100 @@ def test_rejects_negative_max_staleness(self): buf = FakeBuffer() with pytest.raises(ValueError): StalenessSampler(buf, max_staleness_versions=-1) + + def test_rejects_require_order_with_freshest_first(self): + buf = FakeBuffer() + with pytest.raises(ValueError): + StalenessSampler( + buf, + max_staleness_versions=0, + sample_freshest_first=True, + require_order=True, + ) + + +class TestStalenessSamplerReady: + def test_default_mode_skips_unready_slots(self): + buf = FakeBuffer() + buf.add("g0", weight=5, ready=False) + buf.add("g1", weight=5, ready=True) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=1) + ) + + assert selected is not None + assert selected.sample_ids == ["g1_g0"] + assert num_groups == 1 + + def test_default_mode_waits_when_too_few_ready(self): + buf = FakeBuffer() + buf.add("g0", weight=5, ready=False) + buf.add("g1", weight=5, ready=True) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + assert result == (None, 0) + + +class TestStalenessSamplerRequireOrder: + def test_consumes_oldest_batch_first(self): + buf = FakeBuffer() + # Two complete batches: v=4 then v=5; require_order must take v=4 first. + for i, w in enumerate((4, 4, 5, 5)): + buf.add(f"v{w}_{i}", weight=w) + sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) + + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + + assert selected is not None + # Insertion-order FIFO inside the oldest batch. + assert selected.sample_ids == ["v4_0_g0", "v4_1_g0"] + assert num_groups == 2 + assert buf.start_weight_list == [5, 5] + + def test_waits_when_oldest_batch_partially_ready(self): + buf = FakeBuffer() + # Oldest batch v=4 has 1 ready + 1 unready; v=5 batch is fully ready. + # require_order must NOT skip ahead to v=5. + buf.add("v4_a", weight=4, ready=True) + buf.add("v4_b", weight=4, ready=False) + buf.add("v5_a", weight=5, ready=True) + buf.add("v5_b", weight=5, ready=True) + sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) + + result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + assert result == (None, 0) + # Buffer untouched: nothing removed. + assert buf.start_weight_list == [4, 4, 5, 5] + assert buf.ready_list == [True, False, True, True] + + def test_returns_none_when_oldest_batch_not_filled(self): + buf = FakeBuffer() + buf.add("v4_a", weight=4, ready=True) + # Only 1 ready in oldest batch; need 2. + sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) + + result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + assert result == (None, 0) + + def test_ignores_future_versions_when_picking_target(self): + buf = FakeBuffer() + # Trainer at 5, staleness 1: window is [4, 5]; v=7 (future) must not + # become the oldest target. + buf.add("v7", weight=7, ready=True) + buf.add("v5_a", weight=5, ready=True) + buf.add("v5_b", weight=5, ready=True) + sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) + + selected, num_groups = _run( + sampler.select(current_train_weight=5, min_prompt_groups=2) + ) + + assert selected is not None + assert selected.sample_ids == ["v5_a_g0", "v5_b_g0"] + assert num_groups == 2 + assert buf.start_weight_list == [7] diff --git a/tests/unit/single_controller/test_tq_replay_buffer.py b/tests/unit/single_controller/test_tq_replay_buffer.py index 95197e6ff0c..55b45c9eceb 100644 --- a/tests/unit/single_controller/test_tq_replay_buffer.py +++ b/tests/unit/single_controller/test_tq_replay_buffer.py @@ -124,37 +124,118 @@ def _make_buffer(dp: FakeDataPlaneClient) -> TQReplayBuffer: ) -def _add_group(buf: TQReplayBuffer, weight: int) -> KVBatchMeta: - return _run(buf.add(_make_record(), weight_version=weight)) +def _add_group( + buf: TQReplayBuffer, weight: int, end_weight: int | None = None +) -> KVBatchMeta: + if end_weight is None: + end_weight = weight + group_id = buf.reserve(weight_version=weight) + return _run( + buf.commit( + group_id, + _make_record(), + start_weight_version=weight, + end_weight_version=end_weight, + ) + ) + + +class TestTQReplayBufferReserveCommit: + def test_reserve_appends_placeholder_unready(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + group_id = buf.reserve(weight_version=3) -class TestTQReplayBufferAdd: - def test_add_writes_tq_then_appends_meta(self): + assert isinstance(group_id, str) and group_id + assert buf.size() == 1 + assert buf.start_weight_list == [3] + assert buf.end_weight_list == [-1] + assert buf.ready_list == [False] + assert buf.meta_list == [None] + assert dp.depth() == 0 + assert dp.put_calls == [] + + def test_commit_writes_tq_then_fills_meta(self): dp = FakeDataPlaneClient() buf = _make_buffer(dp) - meta = _run(buf.add(_make_record(), weight_version=3)) + group_id = buf.reserve(weight_version=3) + meta = _run( + buf.commit( + group_id, + _make_record(), + start_weight_version=3, + end_weight_version=4, + ) + ) # pack_payload stamps sample_ids as ``{group_uuid}_g{i}``. assert len(meta.sample_ids) == _N_GENS - group_uuid, _, idx = meta.sample_ids[0].rpartition("_g") - assert group_uuid and idx == "0" - assert all(sid.startswith(group_uuid + "_g") for sid in meta.sample_ids) + head, _, idx = meta.sample_ids[0].rpartition("_g") + assert head == group_id and idx == "0" + assert all(sid.startswith(group_id + "_g") for sid in meta.sample_ids) assert dp.depth() == _N_GENS assert buf.size() == 1 - assert buf.weight_list == [3] + assert buf.start_weight_list == [3] + assert buf.end_weight_list == [4] + assert buf.ready_list == [True] assert buf.meta_list[0].sample_ids == meta.sample_ids + # TQ tag uses start_weight_version (dispatch time). assert meta.tags == [{"weight_version": 3}] * _N_GENS assert len(dp.put_calls) == 1 - def test_add_appends_multiple_records_in_order(self): + def test_commit_raises_for_unknown_group_id(self): + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + buf.reserve(weight_version=3) + + with pytest.raises(ValueError): + _run( + buf.commit( + "not-a-real-id", + _make_record(), + start_weight_version=3, + end_weight_version=3, + ) + ) + + def test_reserve_then_commit_preserves_dispatch_order(self): + """Reserve in dispatch order, commit out of order; insertion order holds.""" + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + + weights = (1, 2, 3) + gids = [buf.reserve(weight_version=w) for w in weights] + # Commit out of order: 2, 0, 1 — buffer order must still match reserve order. + for i in (2, 0, 1): + _run( + buf.commit( + gids[i], + _make_record(), + start_weight_version=weights[i], + end_weight_version=weights[i], + ) + ) + + assert buf.size() == 3 + assert buf.start_weight_list == [1, 2, 3] + assert buf.end_weight_list == [1, 2, 3] + assert buf.ready_list == [True, True, True] + # sample_id head equals reserved group_id at each slot. + for i, gid in enumerate(gids): + assert buf.meta_list[i] is not None + assert buf.meta_list[i].sample_ids[0].startswith(gid + "_g") + + def test_commit_appends_multiple_records_in_order(self): dp = FakeDataPlaneClient() buf = _make_buffer(dp) metas = [_add_group(buf, weight=w) for w in (1, 2, 3)] assert buf.size() == 3 - assert buf.weight_list == [1, 2, 3] + assert buf.start_weight_list == [1, 2, 3] + assert buf.end_weight_list == [1, 2, 3] assert [m.sample_ids for m in buf.meta_list] == [ list(metas[0].sample_ids), list(metas[1].sample_ids), @@ -172,7 +253,8 @@ def test_remove_drops_indices_and_clears_dp_when_requested(self): assert n == 2 assert buf.size() == 1 - assert buf.weight_list == [1] + assert buf.start_weight_list == [1] + assert buf.end_weight_list == [1] assert buf.meta_list[0].sample_ids == list(metas[1].sample_ids) assert dp.depth() == _N_GENS assert set(dp._rows) == set(metas[1].sample_ids) @@ -186,7 +268,8 @@ def test_remove_without_dp_keeps_rows(self): assert n == 1 assert buf.size() == 1 - assert buf.weight_list == [1] + assert buf.start_weight_list == [1] + assert buf.end_weight_list == [1] assert buf.meta_list[0].sample_ids == list(metas[1].sample_ids) assert dp.clear_calls == [] assert dp.depth() == 2 * _N_GENS From 87d805dfd4c3cafc76445f64bb2ca3db08b564d4 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sat, 20 Jun 2026 23:48:24 -0700 Subject: [PATCH 08/44] fix config Signed-off-by: Yuki Huang --- tests/functional/grpo_dp_single_controller.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/functional/grpo_dp_single_controller.sh b/tests/functional/grpo_dp_single_controller.sh index 9be3e844f8c..57d35d6a1a1 100755 --- a/tests/functional/grpo_dp_single_controller.sh +++ b/tests/functional/grpo_dp_single_controller.sh @@ -38,13 +38,11 @@ uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJE data_plane.enabled=true \ data_plane.impl=transfer_queue \ data_plane.backend=simple \ - staleness.min_prompt_groups_per_batch=2 \ - staleness.target_prompt_groups_per_step=2 \ - staleness.batch_selection_strategy=strict_on_policy \ - staleness.generations_per_prompt=4 \ - concurrency.max_inflight_prompts=4 \ - concurrency.max_buffered_rollouts=4 \ - training.max_train_steps=2 \ + async_rl.min_prompt_groups_per_batch=2 \ + async_rl.target_prompt_groups_per_step=2 \ + async_rl.batch_selection_strategy=strict_on_policy \ + async_rl.max_inflight_prompts=4 \ + async_rl.max_buffered_rollouts=4 \ $@ \ 2>&1 | tee $RUN_LOG From 4443eccb882c4096128d7ed58a19004df0b58417 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 01:07:28 -0700 Subject: [PATCH 09/44] limit max_train_steps by max_num_epochs Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 1 - .../single_controller_utils/setup.py | 21 ++++++++++++---- .../test_single_controller_setup.py | 24 +++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index dfde1eac0ff..6de5abe306d 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -258,7 +258,6 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: self._inflight_rollouts -= 1 sem.release() - # TODO: limit max_train_steps to max_num_epochs * len(dataloader) when setup max_epochs = self._master_config.grpo["max_num_epochs"] epoch = 0 while max_epochs is None or epoch < max_epochs: diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index b222148ce61..d09e91ff3a9 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -207,14 +207,24 @@ def _generation_max_seq_len(generation_config) -> int: raise ValueError(f"Unknown generation backend: {backend!r}") -def _maybe_inject_megatron_train_iters( +def _clamp_max_num_steps( master_config: MasterConfig, dataloader: StatefulDataLoader ) -> None: - """Mirror grpo_sync's train_iters formula for the Megatron backend. + """Clamp grpo.max_num_steps to max_num_epochs * len(dataloader).""" + grpo_config = master_config.grpo + max_num_epochs = grpo_config.get("max_num_epochs") + if max_num_epochs is None: + return + grpo_config["max_num_steps"] = min( + grpo_config["max_num_steps"], + max_num_epochs * len(dataloader), + ) - Megatron's LR scheduler reads train_iters at TQPolicy.__init__, so - this must run before _build_trainer. - """ + +def _maybe_inject_megatron_train_iters( + master_config: MasterConfig, dataloader: StatefulDataLoader +) -> None: + """Set megatron_cfg.train_iters; must run before _build_trainer.""" policy_config = master_config.policy if not policy_config.get("megatron_cfg", {}).get("enabled", False): return @@ -280,6 +290,7 @@ def setup_single_controller( num_workers=data_config["num_workers"], ) + _clamp_max_num_steps(master_config, dataloader) _maybe_inject_megatron_train_iters(master_config, dataloader) # ========================== diff --git a/tests/unit/single_controller/test_single_controller_setup.py b/tests/unit/single_controller/test_single_controller_setup.py index 1ca6817ef83..96fb9f2d8f0 100644 --- a/tests/unit/single_controller/test_single_controller_setup.py +++ b/tests/unit/single_controller/test_single_controller_setup.py @@ -232,6 +232,30 @@ def test_custom_partition_id(self, patched_factories): "input_ids": 7, } + def test_max_num_steps_capped_by_self(self, patched_factories): + """grpo.max_num_steps stays put when smaller than max_num_epochs * len(dl).""" + mc = _make_master_config( + megatron_enabled=False, + max_num_steps=2, + max_num_epochs=1, + ) + # patched dataloader has len() == 4, so the min picks max_num_steps. + setup_single_controller(mc, MagicMock(pad_token_id=0)) + + assert mc.grpo["max_num_steps"] == 2 + + def test_max_num_steps_capped_by_dataloader_epochs(self, patched_factories): + """grpo.max_num_steps drops to max_num_epochs * len(dataloader) when smaller.""" + mc = _make_master_config( + megatron_enabled=False, + max_num_steps=1000, + max_num_epochs=2, + ) + # patched dataloader has len() == 4 → 2 * 4 = 8 < 1000. + setup_single_controller(mc, MagicMock(pad_token_id=0)) + + assert mc.grpo["max_num_steps"] == 8 + def test_megatron_train_iters_capped_by_max_num_steps(self, patched_factories): """train_iters = min(max_num_steps, max_num_epochs * len(dataloader)).""" mc = _make_master_config( From 462ce21e1df274e5f8aa35485113721fe2e732a1 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 01:07:58 -0700 Subject: [PATCH 10/44] elegant shutdown Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 13 ++++++++++++- nemo_rl/models/generation/vllm/vllm_generation.py | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 6de5abe306d..4263d8fde13 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -148,6 +148,9 @@ def __init__( # Count of in-flight generate_and_push calls self._inflight_rollouts: int = 0 + # Cancellation handles for in-flight rollout dispatches. + self._dispatched_rollouts: set[asyncio.Task[None]] = set() + # over_sampling=False batch gate: farthest trainer_version covered by # already-dispatched batches. self._max_rollout_version: int = -1 @@ -182,11 +185,17 @@ async def run(self) -> dict[str, Any]: await train_task + # Cancel the rollout pump and any in-flight dispatches so we exit immediately. rollout_task.cancel() try: await rollout_task except asyncio.CancelledError: pass + inflight = list(self._dispatched_rollouts) + for task in inflight: + task.cancel() + if inflight: + await asyncio.gather(*inflight, return_exceptions=True) return { "train_steps": self._train_steps, @@ -284,7 +293,9 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: await self._rollout_permitted.wait() # dispatch rollout - asyncio.create_task(_dispatch_one_prompt(prompt)) + task = asyncio.create_task(_dispatch_one_prompt(prompt)) + self._dispatched_rollouts.add(task) + task.add_done_callback(self._dispatched_rollouts.discard) epoch += 1 print(f"rollout_pump: completed {epoch} epoch(s)", flush=True) diff --git a/nemo_rl/models/generation/vllm/vllm_generation.py b/nemo_rl/models/generation/vllm/vllm_generation.py index d68bf512bcc..ce928cd9dba 100644 --- a/nemo_rl/models/generation/vllm/vllm_generation.py +++ b/nemo_rl/models/generation/vllm/vllm_generation.py @@ -905,6 +905,9 @@ def shutdown(self) -> bool: try: # Use the worker group's shutdown method with the worker's cleanup method return self.worker_group.shutdown(cleanup_method="shutdown") + except ray.exceptions.RayActorError: + # Workers already dead (e.g., shut down via another handle to the same actors). + return True except Exception as e: print(f"Error during policy shutdown: {e}") return False From 8b50c27b3f048481dca403ac431cdae4ad501108 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 01:17:35 -0700 Subject: [PATCH 11/44] lint Signed-off-by: Yuki Huang --- tests/unit/experience/test_rollout_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/experience/test_rollout_manager.py b/tests/unit/experience/test_rollout_manager.py index 0542d1a6513..ee1f9921afd 100644 --- a/tests/unit/experience/test_rollout_manager.py +++ b/tests/unit/experience/test_rollout_manager.py @@ -54,7 +54,7 @@ nemo_gym_vllm_generation, # noqa: F401 ) from tests.unit.experience.test_rollouts import ( - initial_multi_step_calculator_batch, # noqa: F401 + initial_multi_step_calculator_batch, # noqa: F401 multi_step_calculator_environment, # noqa: F401 multi_step_setup_vllm_async, # noqa: F401 rollout_cluster, # noqa: F401 From 5f757dd44df6e7f7465264ffc0e1a3bd0b03319e Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 02:39:27 -0700 Subject: [PATCH 12/44] support setup weight_synchronizer and uncomment Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 12 +++++++++--- nemo_rl/algorithms/single_controller_utils/setup.py | 8 +------- nemo_rl/models/policy/lm_policy.py | 10 ++++++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 4263d8fde13..5ce0bd1e17c 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -180,9 +180,14 @@ def __init__( async def run(self) -> dict[str, Any]: """Main entry point. Runs until max_train_steps is reached.""" + # Synchronize weights before starting the pumps + await self._sync_weights() + + # Start the rollout and train pumps rollout_task = asyncio.create_task(self._rollout_pump()) train_task = asyncio.create_task(self._train_pump()) + # Wait until the train pump is done await train_task # Cancel the rollout pump and any in-flight dispatches so we exit immediately. @@ -381,7 +386,6 @@ async def _train_pump(self) -> None: ) break - # TODO: add log result = self._trainer.finish_train_step(step_id) consumed_ids = list(self._step_consumed_sample_ids) self._step_consumed_sample_ids = [] @@ -391,6 +395,9 @@ async def _train_pump(self) -> None: partition_id=self._partition_id, ) + # TODO: add log + print(f"{result=}") + min_sample_version = min(t["weight_version"] for t in train_meta.tags) # type: ignore lag = self._trainer_version - min_sample_version print( @@ -434,8 +441,7 @@ async def _sync_weights(self) -> None: # ) t0 = time.monotonic() - # TODO: currently sync_weights is not implemented, comment out for now - # await self._weight_synchronizer.sync_weights() + await asyncio.to_thread(self._weight_synchronizer.sync_weights) elapsed = time.monotonic() - t0 print(f" _sync_weights: sync done in {elapsed:.3f}s", flush=True) diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index d09e91ff3a9..ba23d8f3374 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -323,12 +323,6 @@ def setup_single_controller( dp_client = build_data_plane_client(dp_cfg, bootstrap=False) backend = generation_config["backend"] - refit_buffer_size_gb = ( - generation_config.get("colocated", {}) - .get("resources", {}) - .get("refit_buffer_size_gb") - ) - # TODO: weight synchronizer not validated yet, placeholder wiring. weight_synchronizer = create_weight_synchronizer( policy=policy, generation=generation, @@ -336,8 +330,8 @@ def setup_single_controller( colocated=colocated, train_cluster=train_cluster, inference_cluster=inference_cluster, - refit_buffer_size_gb=refit_buffer_size_gb, ) + weight_synchronizer.init_communicator() # ========================== # Setup Algorithm + Rollout Wiring diff --git a/nemo_rl/models/policy/lm_policy.py b/nemo_rl/models/policy/lm_policy.py index f1a5d705c06..6eea7497a38 100644 --- a/nemo_rl/models/policy/lm_policy.py +++ b/nemo_rl/models/policy/lm_policy.py @@ -1096,6 +1096,9 @@ def shutdown(self) -> bool: try: # Use the worker group's shutdown method with the worker's cleanup method return self.worker_group.shutdown(cleanup_method="shutdown") + except ray.exceptions.RayActorError: + # Workers already dead (e.g., shut down via another handle to the same actors). + return True except Exception as e: print(f"Error during policy shutdown: {e}") return False @@ -1103,12 +1106,11 @@ def shutdown(self) -> bool: def __del__(self) -> None: """Shuts down the worker groups when the object is deleted or is garbage collected. - This is an extra safety net in case the user forgets to call worker_group.shutdown() and the pointer to + This is an extra safety net in case the user forgets to call shutdown() and the pointer to the object is lost due to leaving a function scope. It's always recommended that the - user calls worker_group.shutdown(). + user calls shutdown(). """ - if hasattr(self, "worker_group"): - self.worker_group.shutdown(cleanup_method="shutdown") + self.shutdown() def start_gpu_profiling(self) -> None: """Start GPU profiling.""" From 37cfcbf3df4996bb0e9957a0ae948043b588f79d Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 05:06:14 -0700 Subject: [PATCH 13/44] feat(single-controller): log per-step train metrics Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 109 +++++----- .../single_controller_utils/utils.py | 189 ++++++++++++++++++ nemo_rl/utils/logger.py | 17 ++ tests/functional/grpo_dp_single_controller.sh | 10 +- 4 files changed, 268 insertions(+), 57 deletions(-) create mode 100644 nemo_rl/algorithms/single_controller_utils/utils.py diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 5ce0bd1e17c..21f87027ec2 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -40,7 +40,6 @@ import ray import torch -from tensordict import TensorDict from nemo_rl.algorithms.async_utils.staleness_sampler import StalenessSampler from nemo_rl.algorithms.single_controller_utils.config import ( @@ -49,8 +48,16 @@ WeightSyncConfig, ) from nemo_rl.algorithms.single_controller_utils.setup import SingleControllerBundle +from nemo_rl.algorithms.single_controller_utils.utils import ( + aggregate_step_metrics, + fields_for_put, + reduce_advantage_pump_metrics, + squeeze_trailing_unit_dim, + tensor_field, +) from nemo_rl.data.interfaces import DatumSpec from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.utils.logger import Logger @ray.remote(num_cpus=1, num_gpus=0) # pragma: no cover @@ -98,6 +105,10 @@ def __init__( # when Ray deserializes rollout_manager and tq_buffer separately. self._rollout_manager._tq_buffer = self._buffer + # Built here, not on the driver: Logger backends (wandb/tb/...) hold + # _thread.lock that Ray can't cloudpickle into the actor. + self._logger = Logger(master_config.logger) + # Pin clusters so RayVirtualCluster.__del__ doesn't remove the PGs. self._train_cluster = bundle.train_cluster self._inference_cluster = bundle.inference_cluster @@ -165,6 +176,11 @@ def __init__( self._trainer_version: int = 0 self._train_steps: int = 0 self._step_consumed_sample_ids: list[str] = [] + self._step_log_dict: dict[str, list] = { + "rewards": [], + "masked_advantages": [], + "sequence_lengths": [], + } print( f"SingleControllerActor: " @@ -189,6 +205,7 @@ async def run(self) -> dict[str, Any]: # Wait until the train pump is done await train_task + self._logger.finish() # Cancel the rollout pump and any in-flight dispatches so we exit immediately. rollout_task.cancel() @@ -379,6 +396,10 @@ async def _train_pump(self) -> None: self._trainer.train_microbatch_from_meta(step_id, train_meta) groups_dispatched += num_groups self._step_consumed_sample_ids.extend(train_meta.sample_ids) + if train_meta.sequence_lengths: + self._step_log_dict["sequence_lengths"].extend( + int(s) for s in train_meta.sequence_lengths + ) if not step_open: print( @@ -395,8 +416,22 @@ async def _train_pump(self) -> None: partition_id=self._partition_id, ) - # TODO: add log - print(f"{result=}") + step_metrics = aggregate_step_metrics(result) + step_metrics.update(reduce_advantage_pump_metrics(**self._step_log_dict)) + self._step_log_dict = {k: [] for k in self._step_log_dict} + + # TODO: wrap _train_pump stages with Timer; emit timing_metrics + # under "timing/train" prefix; add valid_tokens_per_sec_per_gpu + # and print_performance_metrics (see grpo.py:3884-3947). + # TODO: checkpointing (save_period/top-k metric_name, + # policy.save_checkpoint, dataloader state, TQReplayBuffer state). + # TODO: per-step train_data jsonl dump, vllm metrics logger, + # histogram log, rollout_metrics, seq_logprob_error_metrics, + # pretty-print "Training Results" block. + print(f"step_metrics={step_metrics}", flush=True) + self._logger.log_metrics( + step_metrics, step=self._train_steps + 1, prefix="train" + ) min_sample_version = min(t["weight_version"] for t in train_meta.tags) # type: ignore lag = self._trainer_version - min_sample_version @@ -468,13 +503,14 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: select_fields=self._advantage_input_fields(), ) - prompt_ids = _tensor_field(data, adv_cfg.prompt_ids_field) - rewards = _squeeze_trailing_unit_dim( - _tensor_field(data, adv_cfg.reward_field) + prompt_ids = tensor_field(data, adv_cfg.prompt_ids_field) + rewards = squeeze_trailing_unit_dim( + tensor_field(data, adv_cfg.reward_field) ).float() - token_mask = _tensor_field(data, adv_cfg.token_mask_field).float() - sample_mask = _squeeze_trailing_unit_dim( - _tensor_field(data, adv_cfg.sample_mask_field) + self._step_log_dict["rewards"].append(rewards.detach()) + token_mask = tensor_field(data, adv_cfg.token_mask_field).float() + sample_mask = squeeze_trailing_unit_dim( + tensor_field(data, adv_cfg.sample_mask_field) ).float() mask = token_mask * sample_mask.unsqueeze(-1) @@ -482,18 +518,18 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: "total_reward": rewards, } for field_name in adv_cfg.repeated_batch_fields: - repeated_batch[field_name] = _squeeze_trailing_unit_dim( - _tensor_field(data, field_name) + repeated_batch[field_name] = squeeze_trailing_unit_dim( + tensor_field(data, field_name) ) kwargs: dict[str, torch.Tensor] = {} if adv_cfg.policy_logprobs_field is not None: - kwargs["logprobs_policy"] = _tensor_field( + kwargs["logprobs_policy"] = tensor_field( data, adv_cfg.policy_logprobs_field, ) if adv_cfg.reference_logprobs_field is not None: - kwargs["logprobs_reference"] = _tensor_field( + kwargs["logprobs_reference"] = tensor_field( data, adv_cfg.reference_logprobs_field, ) @@ -505,12 +541,15 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: repeated_batch=repeated_batch, **kwargs, ) + self._step_log_dict["masked_advantages"].append( + torch.masked_select(advantages.detach(), mask.bool()) + ) await self._call_dp( "put_samples", sample_ids=meta.sample_ids, partition_id=meta.partition_id, - fields=_fields_for_put( + fields=fields_for_put( meta, {adv_cfg.output_field: advantages}, ), @@ -533,45 +572,3 @@ def _advantage_input_fields(self) -> list[str]: if adv_cfg.reference_logprobs_field is not None: fields.append(adv_cfg.reference_logprobs_field) return list(dict.fromkeys(fields)) - - -def _tensor_field(data: TensorDict, field_name: str) -> torch.Tensor: - value = data[field_name] - if not isinstance(value, torch.Tensor): - raise TypeError( - f"advantage_pump expected tensor field {field_name!r}; got {type(value)}" - ) - if value.is_nested: - return torch.nested.to_padded_tensor(value, padding=0) - return value - - -def _squeeze_trailing_unit_dim(value: torch.Tensor) -> torch.Tensor: - if value.dim() >= 2 and value.shape[-1] == 1: - return value.squeeze(-1) - return value - - -def _fields_for_put(meta: KVBatchMeta, fields: dict[str, torch.Tensor]) -> TensorDict: - packed: dict[str, torch.Tensor] = {} - if meta.sequence_lengths is None: - for field_name, value in fields.items(): - packed[field_name] = value.detach().contiguous() - # pyrefly: ignore[bad-argument-type] - return TensorDict(packed, batch_size=[meta.size]) - - lengths = torch.tensor(meta.sequence_lengths, dtype=torch.long) - for field_name, value in fields.items(): - if value.dim() >= 2 and value.shape[1] == int(lengths.max().item()): - rows = [ - value[i, : int(lengths[i].item())].detach().contiguous() - for i in range(meta.size) - ] - packed[field_name] = torch.nested.as_nested_tensor( - rows, - layout=torch.jagged, - ) - else: - packed[field_name] = value.detach().contiguous() - # pyrefly: ignore[bad-argument-type] - return TensorDict(packed, batch_size=[meta.size]) diff --git a/nemo_rl/algorithms/single_controller_utils/utils.py b/nemo_rl/algorithms/single_controller_utils/utils.py new file mode 100644 index 00000000000..e202d99c4d1 --- /dev/null +++ b/nemo_rl/algorithms/single_controller_utils/utils.py @@ -0,0 +1,189 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Helpers used by SingleControllerActor.""" + +from __future__ import annotations + +from typing import Any + +import numpy as np +import torch +from tensordict import TensorDict + +from nemo_rl.data_plane import KVBatchMeta + +# Reduction rules for all_mb_metrics. Mirror grpo.py / grpo_sync.py. +_MB_METRIC_MIN: frozenset[str] = frozenset( + {"probs_ratio_min", "probs_ratio_clamped_min"} +) +_MB_METRIC_MAX: frozenset[str] = frozenset( + {"probs_ratio_max", "probs_ratio_clamped_max"} +) +_MB_METRIC_MEAN: frozenset[str] = frozenset( + { + "lr", + "wd", + "reward", + "global_valid_seqs", + "global_valid_toks", + "mean_prompt_length", + } +) + + +def aggregate_step_metrics(train_result: dict[str, Any]) -> dict[str, Any]: + """Reduce per-microbatch metric lists into step-level scalars. + + Args: + train_result: Output of TQPolicy.finish_train_step. + + Returns: + Flat dict of step-level scalars ready for logging. + """ + metrics: dict[str, Any] = {} + loss = train_result.get("loss") + if isinstance(loss, torch.Tensor): + metrics["loss"] = loss.detach().mean().item() + elif loss is not None: + metrics["loss"] = float(loss) + grad_norm = train_result.get("grad_norm") + if isinstance(grad_norm, torch.Tensor): + metrics["grad_norm"] = grad_norm.detach().mean().item() + elif grad_norm is not None: + metrics["grad_norm"] = float(grad_norm) + if "total_flops" in train_result: + metrics["total_flops"] = float(train_result["total_flops"]) + if "num_ranks" in train_result: + metrics["num_ranks"] = int(train_result["num_ranks"]) + + # moe/mtp share the same reduction rules as all_mb_metrics in grpo.py. + mb: dict[str, list[Any]] = {} + if "moe_metrics" in train_result: + mb.update({f"moe/{k}": v for k, v in train_result["moe_metrics"].items()}) + if "mtp_metrics" in train_result: + mb.update({f"mtp/{k}": v for k, v in train_result["mtp_metrics"].items()}) + mb.update(train_result.get("all_mb_metrics", {})) + + for k, v in mb.items(): + if k in _MB_METRIC_MIN: + valid = [x for x in v if not np.isinf(x)] + metrics[k] = float(np.min(valid)) if valid else -1.0 + elif k in _MB_METRIC_MAX: + valid = [x for x in v if not np.isinf(x)] + metrics[k] = float(np.max(valid)) if valid else -1.0 + elif k in _MB_METRIC_MEAN: + metrics[k] = float(np.mean(v)) + else: + metrics[k] = float(np.sum(v)) + return metrics + + +def reduce_advantage_pump_metrics( + rewards: list[torch.Tensor], + masked_advantages: list[torch.Tensor], + sequence_lengths: list[int], +) -> dict[str, float]: + """Reduce per-step accumulators from _advantage_pump into step scalars. + + Args: + rewards: One tensor per advantage_pump call; each row a sample reward. + masked_advantages: Token-masked advantages, one tensor per call. + sequence_lengths: All input_lengths trained on this step. + + Returns: + Dict with reward, advantages/{mean,max,min}, total_num_tokens. + """ + out: dict[str, float] = {} + if rewards: + out["reward"] = float(torch.cat([r.flatten() for r in rewards]).mean()) + if masked_advantages: + cat = torch.cat([a.flatten() for a in masked_advantages]) + if cat.numel() > 0: + out["advantages/mean"] = float(cat.mean()) + out["advantages/max"] = float(cat.max()) + out["advantages/min"] = float(cat.min()) + else: + out["advantages/mean"] = 0.0 + out["advantages/max"] = 0.0 + out["advantages/min"] = 0.0 + if sequence_lengths: + out["total_num_tokens"] = float(sum(sequence_lengths)) + return out + + +def tensor_field(data: TensorDict, field_name: str) -> torch.Tensor: + """Read a tensor column from a TensorDict, depadding if nested. + + Args: + data: TensorDict returned by the data plane. + field_name: Column name to fetch. + + Returns: + Dense tensor (nested columns are padded with zeros). + """ + value = data[field_name] + if not isinstance(value, torch.Tensor): + raise TypeError(f"expected tensor field {field_name!r}; got {type(value)}") + if value.is_nested: + return torch.nested.to_padded_tensor(value, padding=0) + return value + + +def squeeze_trailing_unit_dim(value: torch.Tensor) -> torch.Tensor: + """Drop a trailing dim of size 1 if present. + + Args: + value: Input tensor. + + Returns: + Tensor without the trailing unit dim. + """ + if value.dim() >= 2 and value.shape[-1] == 1: + return value.squeeze(-1) + return value + + +def fields_for_put(meta: KVBatchMeta, fields: dict[str, torch.Tensor]) -> TensorDict: + """Pack tensors for DataPlane put, re-nesting jagged rows when needed. + + Args: + meta: Batch meta whose sequence_lengths drive the nesting. + fields: Field name to dense tensor. + + Returns: + TensorDict shaped for dp_client.put_samples. + """ + packed: dict[str, torch.Tensor] = {} + if meta.sequence_lengths is None: + for field_name, value in fields.items(): + packed[field_name] = value.detach().contiguous() + # pyrefly: ignore[bad-argument-type] + return TensorDict(packed, batch_size=[meta.size]) + + lengths = torch.tensor(meta.sequence_lengths, dtype=torch.long) + for field_name, value in fields.items(): + if value.dim() >= 2 and value.shape[1] == int(lengths.max().item()): + rows = [ + value[i, : int(lengths[i].item())].detach().contiguous() + for i in range(meta.size) + ] + packed[field_name] = torch.nested.as_nested_tensor( + rows, + layout=torch.jagged, + ) + else: + packed[field_name] = value.detach().contiguous() + # pyrefly: ignore[bad-argument-type] + return TensorDict(packed, batch_size=[meta.size]) diff --git a/nemo_rl/utils/logger.py b/nemo_rl/utils/logger.py index c00fa96b9b4..caf973a3c54 100644 --- a/nemo_rl/utils/logger.py +++ b/nemo_rl/utils/logger.py @@ -393,6 +393,16 @@ def log_plot(self, figure: plt.Figure, step: int, name: str) -> None: """ self.run.log({name: figure}, step=step) + def finish(self) -> None: + """Flush queued metrics and close the wandb service. + + Required when the run lives inside a Ray actor: Ray tears the worker + down before wandb's atexit hook can drain the IPC queue to the service. + """ + if self.run is not None: + self.run.finish() + self.run = None + def log_histogram(self, histogram: list[Any], step: int, name: str) -> None: """Log histogram metrics to wandb. @@ -1038,6 +1048,13 @@ def log_hyperparams(self, params: Mapping[str, Any]) -> None: for logger in self.loggers: logger.log_hyperparams(params) + def finish(self) -> None: + """Flush and close backends that need explicit teardown (e.g. wandb).""" + for logger in self.loggers: + finish = getattr(logger, "finish", None) + if callable(finish): + finish() + def log_batched_dict_as_jsonl( self, to_log: BatchedDataDict[Any] | dict[str, Any], filename: str ) -> None: diff --git a/tests/functional/grpo_dp_single_controller.sh b/tests/functional/grpo_dp_single_controller.sh index 57d35d6a1a1..8ec7fd83e26 100755 --- a/tests/functional/grpo_dp_single_controller.sh +++ b/tests/functional/grpo_dp_single_controller.sh @@ -14,6 +14,7 @@ set -eou pipefail EXP_NAME=$(basename $0 .sh) EXP_DIR=$SCRIPT_DIR/$EXP_NAME LOG_DIR=$EXP_DIR/logs +JSON_METRICS=$EXP_DIR/metrics.json RUN_LOG=$EXP_DIR/run.log export PYTHONPATH=${PROJECT_ROOT}:${PYTHONPATH:-} @@ -46,4 +47,11 @@ uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJE $@ \ 2>&1 | tee $RUN_LOG -# TODO: add metrics +uv run tests/json_dump_tb_logs.py $LOG_DIR --output_path $JSON_METRICS + +uv run tests/check_metrics.py $JSON_METRICS \ + 'max(data["train/gen_kl_error"]) < 0.002' \ + 'min(data["train/probs_ratio_clamped_min"]) > 0.79' \ + 'max(data["train/probs_ratio_clamped_min"]) < 1.21' \ + 'min(data["train/probs_ratio_clamped_max"]) > 0.79' \ + 'max(data["train/probs_ratio_clamped_max"]) < 1.21' From c56cf476b00008fb9b7e1dfab67c3f4af57f0374 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 05:55:03 -0700 Subject: [PATCH 14/44] add prepare_for_lp/training Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 21f87027ec2..764b3d2c9b0 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -36,7 +36,7 @@ import asyncio import time -from typing import Any +from typing import Any, Union import ray import torch @@ -57,8 +57,13 @@ ) from nemo_rl.data.interfaces import DatumSpec from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.models.generation.sglang import SGLangGeneration +from nemo_rl.models.generation.vllm import VllmGeneration +from nemo_rl.models.policy.tq_policy import TQPolicy from nemo_rl.utils.logger import Logger +Generation = Union[VllmGeneration, SGLangGeneration] + @ray.remote(num_cpus=1, num_gpus=0) # pragma: no cover class SingleControllerActor: @@ -93,8 +98,8 @@ def __init__( self._master_config = master_config self._async_cfg = master_config.async_rl self._dp_client = bundle.dp_client - self._gen = bundle.gen_handle - self._trainer = bundle.trainer_handle + self._gen: Generation = bundle.gen_handle + self._trainer: TQPolicy = bundle.trainer_handle self._dataloader = bundle.dataloader self._weight_synchronizer = bundle.weight_synchronizer self._advantage_estimator = bundle.advantage_estimator @@ -107,7 +112,7 @@ def __init__( # Built here, not on the driver: Logger backends (wandb/tb/...) hold # _thread.lock that Ray can't cloudpickle into the actor. - self._logger = Logger(master_config.logger) + self._logger = Logger(master_config.logger) # type: ignore # Pin clusters so RayVirtualCluster.__del__ doesn't remove the PGs. self._train_cluster = bundle.train_cluster @@ -378,22 +383,24 @@ async def _train_pump(self) -> None: self._buffer_capacity.release() # Compute prev_logprobs / ref_logprobs + self._trainer.prepare_for_lp_inference() if compute_prev_logprobs: self._trainer.get_logprobs_from_meta(train_meta) - if compute_reference_logprobs: self._trainer.get_reference_policy_logprobs_from_meta(train_meta) train_meta = await self._advantage_pump(train_meta) + # Train + self._trainer.prepare_for_training() if not step_open: self._trainer.begin_train_step(step_id, loss_fn=self._loss_fn) step_open = True - # Driver-side TQPolicy blocks until worker results land; we drop # the per-microbatch dict and surface aggregated metrics from # finish_train_step instead. self._trainer.train_microbatch_from_meta(step_id, train_meta) + groups_dispatched += num_groups self._step_consumed_sample_ids.extend(train_meta.sample_ids) if train_meta.sequence_lengths: From cfaaeebfc47e5a86d7826445a86b57b3383e7de8 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 06:29:10 -0700 Subject: [PATCH 15/44] add nightly Signed-off-by: Yuki Huang --- ...uct-2n8g-async-1off-single-controller.yaml | 32 ++++++++++++++ ...truct-2n8g-async-1off-single-controller.sh | 42 +++++++++++++++++++ tests/test_suites/nightly.txt | 3 ++ 3 files changed, 77 insertions(+) create mode 100644 examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml create mode 100755 tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh diff --git a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml new file mode 100644 index 00000000000..a8f4a60d492 --- /dev/null +++ b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml @@ -0,0 +1,32 @@ +# SingleController variant of grpo-llama3.1-8b-instruct-2n8g-async-1off.yaml. +# Same training topology and async-1off strategy; the SC path routes +# everything through the TransferQueue data plane + SingleControllerActor. +# staleness_window + over_sampling=false replicate the per-version dispatch +# quota of the original async-grpo path. +defaults: ./performance/grpo-llama3.1-8b-instruct-2n8g-async-1off.yaml + +logger: + log_dir: logs/grpo-llama3.1-8b-instruct-2n8g-async-1off-sc + wandb: + name: grpo-llama3.1-8b-instruct-2n8g-async-1off-sc + +checkpointing: + checkpoint_dir: results/grpo-llama3.1-8b-instruct-2n8g-async-1off-sc + +# TransferQueue data plane is mandatory for the SingleController path. +data_plane: + enabled: true + +# SC async-RL runtime knobs. +async_rl: + # Matches grpo.async_grpo.max_trajectory_age_steps=1. + max_weight_staleness_versions: 1 + # One training step consumes grpo.num_prompts_per_step (=64) prompt groups. + min_prompt_groups_per_batch: 64 + batch_selection_strategy: staleness_window + max_inflight_prompts: 128 + # over_sampling=false requires + # max_buffered_rollouts == target_prompt_groups_per_step * (max_weight_staleness_versions + 1) + # 64 * (1 + 1) = 128 + max_buffered_rollouts: 128 + over_sampling: false diff --git a/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh b/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh new file mode 100755 index 00000000000..7476f62fcfc --- /dev/null +++ b/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh @@ -0,0 +1,42 @@ +#!/bin/bash +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source $SCRIPT_DIR/common.env + +# ===== BEGIN CONFIG ===== +NUM_NODES=2 +STEPS_PER_RUN=10 +MAX_STEPS=10 +NUM_RUNS=$(( (MAX_STEPS + STEPS_PER_RUN - 1) / STEPS_PER_RUN )) # Round up +NUM_MINUTES=100 +# ===== END CONFIG ===== + +exit_if_max_steps_reached + +# Run the experiment +cd $PROJECT_ROOT +uv run examples/run_grpo_single_controller.py \ + --config $CONFIG_PATH \ + grpo.max_num_steps=$MAX_STEPS \ + logger.log_dir=$LOG_DIR \ + logger.wandb_enabled=True \ + logger.wandb.project=nemo-rl \ + logger.wandb.name=$EXP_NAME \ + logger.monitor_gpus=True \ + logger.tensorboard_enabled=True \ + checkpointing.enabled=True \ + checkpointing.checkpoint_dir=$CKPT_DIR \ + $@ \ + 2>&1 | tee $RUN_LOG + +# Convert tensorboard logs to json +uv run tests/json_dump_tb_logs.py $LOG_DIR --output_path $JSON_METRICS + +# Only run metrics if the target step is reached +if [[ $(jq 'to_entries | .[] | select(.key == "train/loss") | .value | keys | map(tonumber) | max' $JSON_METRICS) -ge $MAX_STEPS ]]; then + uv run tests/check_metrics.py $JSON_METRICS \ + 'median(data["train/token_mult_prob_error"]) < 1.1' \ + 'data["train/token_mult_prob_error"]["10"] < 1.1' + + # Clean up checkpoint directory after successful run to save space. + rm -rf "$CKPT_DIR" +fi diff --git a/tests/test_suites/nightly.txt b/tests/test_suites/nightly.txt index 2c2fa417dd4..60a7f68ee26 100644 --- a/tests/test_suites/nightly.txt +++ b/tests/test_suites/nightly.txt @@ -145,6 +145,9 @@ tests/test_suites/llm/grpo-nanov3-30BA3B-2n8g-fsdp2-tq_mooncake.sh tests/test_suites/llm/grpo-qwen3-8B-base-1n8g-fsdp2-lora-tq_mooncake.sh tests/test_suites/llm/prorlv2-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v2-tq_mooncake.sh +# Single Contoller (SC) +tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh + ######## # DAPO # ######## From 5ad58e3d53cec527e1e7e4b4cc991ec88681ac00 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 06:29:54 -0700 Subject: [PATCH 16/44] copyright Signed-off-by: Yuki Huang --- .../single_controller/test_rollout_pump.py | 7 +----- .../test_single_controller_setup.py | 23 ++++++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index 62d13bc1525..3fcf9a3db43 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -12,12 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""End-to-end test: SC._rollout_pump writes the expected rows to TQ. - -Reuses test_async_rollout_manager's fixtures (real vLLM, env, tokenizer, -DatumSpec). dp_client is a NoOpDataPlaneClient wrapped in a Ray actor so the -test process can inspect TQ state after the SC actor finishes. -""" +"""End-to-end test: SC._rollout_pump writes the expected rows to TQ.""" from __future__ import annotations diff --git a/tests/unit/single_controller/test_single_controller_setup.py b/tests/unit/single_controller/test_single_controller_setup.py index 96fb9f2d8f0..1f526bd0558 100644 --- a/tests/unit/single_controller/test_single_controller_setup.py +++ b/tests/unit/single_controller/test_single_controller_setup.py @@ -1,11 +1,18 @@ -"""Unit tests for setup_single_controller. - -setup_single_controller is heavy (it spins up Ray clusters, TQPolicy, generation -backend, ...) so it's exercised through monkey-patching rather than as a real e2e — -the unit tests cover the shape of the contract, not the underlying initialization. -The full path is covered by the functional test at -tests/functional/grpo_dp_single_controller.sh. -""" +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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 setup_single_controller (factories monkey-patched).""" from __future__ import annotations From e05861b24d0afc4ce2abd07de9f3becc2d66ab56 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 06:56:11 -0700 Subject: [PATCH 17/44] add timing Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 182 +++++++++++++++--------- 1 file changed, 111 insertions(+), 71 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 764b3d2c9b0..afd72095392 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -61,6 +61,7 @@ from nemo_rl.models.generation.vllm import VllmGeneration from nemo_rl.models.policy.tq_policy import TQPolicy from nemo_rl.utils.logger import Logger +from nemo_rl.utils.timer import Timer Generation = Union[VllmGeneration, SGLangGeneration] @@ -113,6 +114,7 @@ def __init__( # Built here, not on the driver: Logger backends (wandb/tb/...) hold # _thread.lock that Ray can't cloudpickle into the actor. self._logger = Logger(master_config.logger) # type: ignore + self._timer = Timer() # Pin clusters so RayVirtualCluster.__del__ doesn't remove the PGs. self._train_cluster = bundle.train_cluster @@ -356,104 +358,142 @@ async def _train_pump(self) -> None: groups_dispatched = 0 step_open = False - while groups_dispatched < target_groups: - await asyncio.sleep(0) + with self._timer.time("total_step_time"): + while groups_dispatched < target_groups: + await asyncio.sleep(0) - # evict stale groups - evicted = await self._sampler.evict( - current_train_weight=self._trainer_version, - ) - if evicted: - print(f" evicted {evicted} stale prompt group(s)", flush=True) - for _ in range(evicted): + # evict stale groups + evicted = await self._sampler.evict( + current_train_weight=self._trainer_version, + ) + if evicted: + print(f" evicted {evicted} stale prompt group(s)", flush=True) + for _ in range(evicted): + self._buffer_capacity.release() + + # TODO @yukih: wait train pump merged, now always return min_prompt_groups_per_batch + # need to add a max_prompt_groups_per_batch + with self._timer.time("exposed_generation"): + train_meta, num_groups = await self._sampler.select( + current_train_weight=self._trainer_version, + min_prompt_groups=self._async_cfg.min_prompt_groups_per_batch, + ) + + if train_meta is None: + await asyncio.sleep(0.05) + continue + + for _ in range(num_groups): self._buffer_capacity.release() - # TODO @yukih: wait train pump merged, now always return min_prompt_groups_per_batch - # need to add a max_prompt_groups_per_batch - train_meta, num_groups = await self._sampler.select( - current_train_weight=self._trainer_version, - min_prompt_groups=self._async_cfg.min_prompt_groups_per_batch, - ) - - if train_meta is None: - await asyncio.sleep(0.05) - continue - - for _ in range(num_groups): - self._buffer_capacity.release() - - # Compute prev_logprobs / ref_logprobs - self._trainer.prepare_for_lp_inference() - if compute_prev_logprobs: - self._trainer.get_logprobs_from_meta(train_meta) - if compute_reference_logprobs: - self._trainer.get_reference_policy_logprobs_from_meta(train_meta) - - train_meta = await self._advantage_pump(train_meta) + # Compute prev_logprobs / ref_logprobs + with self._timer.time("logprob_inference_prep"): + self._trainer.prepare_for_lp_inference() + with self._timer.time("policy_and_reference_logprobs"): + if compute_prev_logprobs: + self._trainer.get_logprobs_from_meta(train_meta) + if compute_reference_logprobs: + self._trainer.get_reference_policy_logprobs_from_meta( + train_meta + ) + + with self._timer.time("advantage_calculation"): + train_meta = await self._advantage_pump(train_meta) + + # Train + with self._timer.time("training_prep"): + self._trainer.prepare_for_training() + with self._timer.time("policy_training"): + if not step_open: + self._trainer.begin_train_step( + step_id, loss_fn=self._loss_fn + ) + step_open = True + self._trainer.train_microbatch_from_meta(step_id, train_meta) + + groups_dispatched += num_groups + self._step_consumed_sample_ids.extend(train_meta.sample_ids) + if train_meta.sequence_lengths: + self._step_log_dict["sequence_lengths"].extend( + int(s) for s in train_meta.sequence_lengths + ) - # Train - self._trainer.prepare_for_training() if not step_open: - self._trainer.begin_train_step(step_id, loss_fn=self._loss_fn) - step_open = True - # Driver-side TQPolicy blocks until worker results land; we drop - # the per-microbatch dict and surface aggregated metrics from - # finish_train_step instead. - self._trainer.train_microbatch_from_meta(step_id, train_meta) - - groups_dispatched += num_groups - self._step_consumed_sample_ids.extend(train_meta.sample_ids) - if train_meta.sequence_lengths: - self._step_log_dict["sequence_lengths"].extend( - int(s) for s in train_meta.sequence_lengths + print( + "train_pump: rollout exhausted before any group ready", + flush=True, ) + break + + with self._timer.time("policy_training"): + result = self._trainer.finish_train_step(step_id) + consumed_ids = list(self._step_consumed_sample_ids) + self._step_consumed_sample_ids = [] + await self._call_dp( + "clear_samples", + sample_ids=list(consumed_ids), + partition_id=self._partition_id, + ) - if not step_open: - print( - "train_pump: rollout exhausted before any group ready", flush=True + step_metrics = aggregate_step_metrics(result) + step_metrics.update( + reduce_advantage_pump_metrics(**self._step_log_dict) + ) + self._step_log_dict = {k: [] for k in self._step_log_dict} + + self._trainer_version += 1 + self._train_steps += 1 + with self._timer.time("weight_sync"): + await self._sync_weights() + + timing_metrics: dict[str, float] = self._timer.get_timing_metrics( + reduction_op="sum" + ) # type: ignore + + total_time = timing_metrics.get("total_step_time", 0.0) + cluster_cfg = self._master_config.cluster + total_num_gpus = cluster_cfg["num_nodes"] * cluster_cfg["gpus_per_node"] + if total_time > 0 and "global_valid_toks" in step_metrics: + timing_metrics["valid_tokens_per_sec_per_gpu"] = ( + step_metrics["global_valid_toks"] / total_time / total_num_gpus ) - break - - result = self._trainer.finish_train_step(step_id) - consumed_ids = list(self._step_consumed_sample_ids) - self._step_consumed_sample_ids = [] - await self._call_dp( - "clear_samples", - sample_ids=list(consumed_ids), - partition_id=self._partition_id, - ) - step_metrics = aggregate_step_metrics(result) - step_metrics.update(reduce_advantage_pump_metrics(**self._step_log_dict)) - self._step_log_dict = {k: [] for k in self._step_log_dict} + print("\n⏱️ Timing:") + print(f" • Total step time: {total_time:.2f}s") + for k, v in sorted( + timing_metrics.items(), key=lambda item: item[1], reverse=True + ): + if k == "total_step_time": + continue + percent = (v / total_time * 100) if total_time > 0 else 0.0 + print(f" • {k}: {v:.2f}s ({percent:.1f}%)") - # TODO: wrap _train_pump stages with Timer; emit timing_metrics - # under "timing/train" prefix; add valid_tokens_per_sec_per_gpu - # and print_performance_metrics (see grpo.py:3884-3947). # TODO: checkpointing (save_period/top-k metric_name, # policy.save_checkpoint, dataloader state, TQReplayBuffer state). # TODO: per-step train_data jsonl dump, vllm metrics logger, # histogram log, rollout_metrics, seq_logprob_error_metrics, - # pretty-print "Training Results" block. + # pretty-print "Training Results" block, print_performance_metrics. print(f"step_metrics={step_metrics}", flush=True) self._logger.log_metrics( - step_metrics, step=self._train_steps + 1, prefix="train" + step_metrics, step=self._train_steps, prefix="train" ) + self._logger.log_metrics( + timing_metrics, step=self._train_steps, prefix="timing/train" + ) + self._timer.reset() + # min sample version refers to the version each consumed sample was + # generated with; lag = current trainer version - oldest sample version. min_sample_version = min(t["weight_version"] for t in train_meta.tags) # type: ignore lag = self._trainer_version - min_sample_version print( - f"train step {self._train_steps + 1}/{grpo_cfg['max_num_steps']} " + f"train step {self._train_steps}/{grpo_cfg['max_num_steps']} " f"trainer_v={self._trainer_version} " f"lag={lag} " f"batch_size={len(consumed_ids)}", flush=True, ) - self._trainer_version += 1 - self._train_steps += 1 - await self._sync_weights() - async def _sync_weights(self) -> None: """Drain in-flight rollouts then synchronize weights. From 3c51421bedfea2d9430fa8d77a96714428f9ce1e Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 21 Jun 2026 08:25:15 -0700 Subject: [PATCH 18/44] add nightly sync Signed-off-by: Yuki Huang --- ...truct-1n8g-megatron-single-controller.yaml | 47 +++++++++++++++++++ nemo_rl/algorithms/single_controller.py | 3 +- ...nstruct-1n8g-megatron-single-controller.sh | 43 +++++++++++++++++ tests/test_suites/nightly.txt | 1 + 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml create mode 100755 tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh diff --git a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml new file mode 100644 index 00000000000..9890c883a12 --- /dev/null +++ b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml @@ -0,0 +1,47 @@ +# SingleController + Megatron variant of grpo-qwen2.5-math-1.5b-instruct-1n8g. +# SC currently only supports non-colocated generation; the 8 GPUs on the node +# are split 4 (train) + 4 (inference). The SC path routes everything through +# the TransferQueue data plane + SingleControllerActor. strict_on_policy +# auto-sets max_weight_staleness_versions=0 and over_sampling=False, enforcing +# a strict per-version dispatch quota. +defaults: ./grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v3.yaml + +logger: + log_dir: logs/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-sc + wandb: + name: grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-sc + +checkpointing: + checkpoint_dir: results/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-sc + +# TransferQueue data plane is mandatory for the SingleController path. +data_plane: + enabled: true + +# SC async-RL runtime knobs. +async_rl: + # One training step consumes grpo.num_prompts_per_step (=32) prompt groups. + min_prompt_groups_per_batch: 32 + batch_selection_strategy: strict_on_policy + max_inflight_prompts: 64 + # strict_on_policy auto-sets max_weight_staleness_versions=0 and + # over_sampling=False. over_sampling=false requires + # max_buffered_rollouts == target_prompt_groups_per_step * (max_weight_staleness_versions + 1) + # 32 * (0 + 1) = 32 + max_buffered_rollouts: 32 + over_sampling: false + +policy: + dtensor_cfg: + enabled: false + megatron_cfg: + enabled: true + generation: + vllm_cfg: + async_engine: true + colocated: + enabled: false + resources: + # 4 GPUs for inference; remaining 4 GPUs on the node go to training. + gpus_per_node: 4 + num_nodes: 1 diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index afd72095392..e17a89cff38 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -135,8 +135,9 @@ def __init__( if self._async_cfg.batch_selection_strategy == "strict_on_policy": self._async_cfg.max_weight_staleness_versions = 0 + self._async_cfg.over_sampling = False print( - "Using strict_on_policy, auto setting max_weight_staleness_versions to 0.", + "Using strict_on_policy, auto setting max_weight_staleness_versions to 0 and over_sampling to False.", flush=True, ) diff --git a/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh b/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh new file mode 100755 index 00000000000..96b5758dfc2 --- /dev/null +++ b/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh @@ -0,0 +1,43 @@ +#!/bin/bash +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source $SCRIPT_DIR/common.env + +# ===== BEGIN CONFIG ===== +NUM_NODES=1 +STEPS_PER_RUN=450 +MAX_STEPS=450 +NUM_RUNS=$(( (MAX_STEPS + STEPS_PER_RUN - 1) / STEPS_PER_RUN )) # Round up +NUM_MINUTES=240 +# ===== END CONFIG ===== + +exit_if_max_steps_reached + +# Run the experiment +cd $PROJECT_ROOT +uv run examples/run_grpo_single_controller.py \ + --config $CONFIG_PATH \ + grpo.max_num_steps=$MAX_STEPS \ + logger.log_dir=$LOG_DIR \ + logger.wandb_enabled=True \ + logger.wandb.project=nemo-rl \ + logger.wandb.name=$EXP_NAME \ + logger.monitor_gpus=True \ + logger.tensorboard_enabled=True \ + checkpointing.enabled=True \ + checkpointing.checkpoint_dir=$CKPT_DIR \ + $@ \ + 2>&1 | tee $RUN_LOG + +# Convert tensorboard logs to json +uv run tests/json_dump_tb_logs.py $LOG_DIR --output_path $JSON_METRICS + +# Only run metrics if the target step is reached +if [[ $(jq 'to_entries | .[] | select(.key == "train/loss") | .value | keys | map(tonumber) | max' $JSON_METRICS) -ge $MAX_STEPS ]]; then + uv run tests/check_metrics.py $JSON_METRICS \ + 'median(data["train/token_mult_prob_error"]) < 1.1' \ + 'data["train/token_mult_prob_error"]["450"] < 1.1' \ + 'mean(data["timing/train/total_step_time"], 2) < 25' + + # Clean up checkpoint directory after successful run to save space. + rm -rf "$CKPT_DIR" +fi diff --git a/tests/test_suites/nightly.txt b/tests/test_suites/nightly.txt index 60a7f68ee26..3653ae1a909 100644 --- a/tests/test_suites/nightly.txt +++ b/tests/test_suites/nightly.txt @@ -147,6 +147,7 @@ tests/test_suites/llm/prorlv2-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v2-tq_moo # Single Contoller (SC) tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh +tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh ######## # DAPO # From 888cb8eebf0fb5698879085303047b32bef9b3c6 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Mon, 22 Jun 2026 02:10:29 -0700 Subject: [PATCH 19/44] fix(sc): unblock train_pump asyncio, add set_seed, fix LR log ordering Signed-off-by: Yuki Huang --- ...uct-2n8g-async-1off-single-controller.yaml | 2 +- ...truct-1n8g-megatron-single-controller.yaml | 2 ++ nemo_rl/algorithms/single_controller.py | 29 +++++++++++++------ .../single_controller_utils/setup.py | 3 ++ .../policy/workers/megatron_policy_worker.py | 6 ++-- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml index a8f4a60d492..8cc5b4464b5 100644 --- a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml @@ -24,7 +24,7 @@ async_rl: # One training step consumes grpo.num_prompts_per_step (=64) prompt groups. min_prompt_groups_per_batch: 64 batch_selection_strategy: staleness_window - max_inflight_prompts: 128 + max_inflight_prompts: ${grpo.num_prompts_per_step} # match grpo-llama3.1-8b-instruct-2n8g-async-1off # over_sampling=false requires # max_buffered_rollouts == target_prompt_groups_per_step * (max_weight_staleness_versions + 1) # 64 * (1 + 1) = 128 diff --git a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml index 9890c883a12..eae1c00d09c 100644 --- a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml @@ -36,6 +36,8 @@ policy: enabled: false megatron_cfg: enabled: true + scheduler: + lr_warmup_iters: 50 generation: vllm_cfg: async_engine: true diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index e17a89cff38..23725f1f16a 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -389,13 +389,16 @@ async def _train_pump(self) -> None: # Compute prev_logprobs / ref_logprobs with self._timer.time("logprob_inference_prep"): - self._trainer.prepare_for_lp_inference() + await asyncio.to_thread(self._trainer.prepare_for_lp_inference) with self._timer.time("policy_and_reference_logprobs"): if compute_prev_logprobs: - self._trainer.get_logprobs_from_meta(train_meta) + await asyncio.to_thread( + self._trainer.get_logprobs_from_meta, train_meta + ) if compute_reference_logprobs: - self._trainer.get_reference_policy_logprobs_from_meta( - train_meta + await asyncio.to_thread( + self._trainer.get_reference_policy_logprobs_from_meta, + train_meta, ) with self._timer.time("advantage_calculation"): @@ -403,14 +406,20 @@ async def _train_pump(self) -> None: # Train with self._timer.time("training_prep"): - self._trainer.prepare_for_training() + await asyncio.to_thread(self._trainer.prepare_for_training) with self._timer.time("policy_training"): if not step_open: - self._trainer.begin_train_step( - step_id, loss_fn=self._loss_fn + await asyncio.to_thread( + self._trainer.begin_train_step, + step_id, + loss_fn=self._loss_fn, ) step_open = True - self._trainer.train_microbatch_from_meta(step_id, train_meta) + await asyncio.to_thread( + self._trainer.train_microbatch_from_meta, + step_id, + train_meta, + ) groups_dispatched += num_groups self._step_consumed_sample_ids.extend(train_meta.sample_ids) @@ -427,7 +436,9 @@ async def _train_pump(self) -> None: break with self._timer.time("policy_training"): - result = self._trainer.finish_train_step(step_id) + result = await asyncio.to_thread( + self._trainer.finish_train_step, step_id + ) consumed_ids = list(self._step_consumed_sample_ids) self._step_consumed_sample_ids = [] await self._call_dp( diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index ba23d8f3374..07431e4d750 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -34,6 +34,7 @@ from nemo_rl.algorithms.loss import ClippedPGLossFn from nemo_rl.algorithms.loss.interfaces import LossFunction from nemo_rl.algorithms.single_controller_utils.config import MasterConfig +from nemo_rl.algorithms.utils import set_seed from nemo_rl.data.collate_fn import rl_collate_fn from nemo_rl.data.utils import setup_response_data from nemo_rl.data_plane import build_data_plane_client @@ -274,6 +275,8 @@ def setup_single_controller( "data.use_multiple_dataloader=True yet." ) + set_seed(grpo_config["seed"]) + # ========================== # Setup Dataset & Environments # ========================== diff --git a/nemo_rl/models/policy/workers/megatron_policy_worker.py b/nemo_rl/models/policy/workers/megatron_policy_worker.py index 94a74514131..a13e4943732 100644 --- a/nemo_rl/models/policy/workers/megatron_policy_worker.py +++ b/nemo_rl/models/policy/workers/megatron_policy_worker.py @@ -1137,6 +1137,10 @@ def finish_train_step(self, step_id: str) -> dict[str, Any]: finish_model_config.grad_sync_func = state["saved_grad_sync_func"] finish_model_config.no_sync_func = state["saved_no_sync_func"] + # Record the LR/WD before self.scheduler.step() is called. + curr_lr = self.scheduler.get_lr(self.optimizer.param_groups[0]) + curr_wd = self.scheduler.get_wd() + # Scheduler increment matches sync path's ``increment=gbs``. self.scheduler.step(increment=state["gbs"]) @@ -1144,8 +1148,6 @@ def finish_train_step(self, step_id: str) -> dict[str, Any]: # sync path produces. ``masked_mean`` is linear in 1/N so a single # scalar multiply per metric recovers the normalized value. rescaled_metrics: list[dict[str, Any]] = [] - curr_lr = self.scheduler.get_lr(self.optimizer.param_groups[0]) - curr_wd = self.scheduler.get_wd() global_valid_seqs_f = float(global_valid_seqs.item()) global_valid_toks_f = float(global_valid_toks.item()) From d515ddb802ef80c6b158cb5341083dd91a5d9fd5 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Mon, 22 Jun 2026 03:06:56 -0700 Subject: [PATCH 20/44] feat(sc): add force_in_order target-step matching to async_rl sampler Signed-off-by: Yuki Huang --- ...uct-2n8g-async-1off-single-controller.yaml | 1 + .../algorithms/async_utils/replay_buffer.py | 13 +++- .../async_utils/staleness_sampler.py | 62 ++++++++++++------- nemo_rl/algorithms/single_controller.py | 25 ++++++-- .../single_controller_utils/config.py | 4 ++ nemo_rl/experience/rollout_manager.py | 9 ++- 6 files changed, 83 insertions(+), 31 deletions(-) diff --git a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml index 8cc5b4464b5..8e12944aec6 100644 --- a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml @@ -30,3 +30,4 @@ async_rl: # 64 * (1 + 1) = 128 max_buffered_rollouts: 128 over_sampling: false + force_in_order: true diff --git a/nemo_rl/algorithms/async_utils/replay_buffer.py b/nemo_rl/algorithms/async_utils/replay_buffer.py index bc3ef251af2..cab8685de75 100644 --- a/nemo_rl/algorithms/async_utils/replay_buffer.py +++ b/nemo_rl/algorithms/async_utils/replay_buffer.py @@ -577,14 +577,23 @@ def __init__( self.meta_list: list[Optional[KVBatchMeta]] = [] self.start_weight_list: list[int] = [] self.end_weight_list: list[int] = [] + # Per-slot target training step (set when force_in_order=True, else None). + self.target_step_list: list[Optional[int]] = [] self.ready_list: list[bool] = [] self._group_ids: list[str] = [] - def reserve(self, *, weight_version: int, group_id: Optional[str] = None) -> str: + def reserve( + self, + *, + weight_version: int, + target_step: Optional[int] = None, + group_id: Optional[str] = None, + ) -> str: """Append an unready slot tagged with weight_version. Args: weight_version: Weight version stamped on the slot. + target_step: Training step this slot targets; only consulted by StalenessSampler.force_in_order. group_id: Per-group sample_id prefix; defaults to a fresh uuid4. Returns: @@ -595,6 +604,7 @@ def reserve(self, *, weight_version: int, group_id: Optional[str] = None) -> str self.meta_list.append(None) self.start_weight_list.append(weight_version) self.end_weight_list.append(-1) + self.target_step_list.append(target_step) self.ready_list.append(False) self._group_ids.append(group_id) return group_id @@ -678,6 +688,7 @@ async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: del self.meta_list[i] del self.start_weight_list[i] del self.end_weight_list[i] + del self.target_step_list[i] del self.ready_list[i] del self._group_ids[i] diff --git a/nemo_rl/algorithms/async_utils/staleness_sampler.py b/nemo_rl/algorithms/async_utils/staleness_sampler.py index 63d5f19225b..eae88d6b946 100644 --- a/nemo_rl/algorithms/async_utils/staleness_sampler.py +++ b/nemo_rl/algorithms/async_utils/staleness_sampler.py @@ -19,11 +19,14 @@ class StalenessSampler: - """Pick complete prompt groups inside a version staleness window. - - sample_freshest_first prefers smallest lag; require_order takes only from - the oldest weight_version present and waits for its batch to fill. Unready - slots are always skipped. + """Pick complete prompt groups from a TQReplayBuffer. + + Args: + buffer: Shared TQReplayBuffer holding the candidate slots. + max_staleness_versions: Max weight-version gap a sample may have from the trainer. + sample_freshest_first: Prefer smallest lag when picking from the in-window set. + require_order: Take only from the oldest in-window weight_version and wait for its batch to fill. + force_in_order: Match each slot's target_step against current_train_weight, ignoring the window; mirrors legacy async_grpo target_weight semantics. """ def __init__( @@ -32,6 +35,7 @@ def __init__( max_staleness_versions: int, sample_freshest_first: bool = False, require_order: bool = False, + force_in_order: bool = False, ) -> None: if max_staleness_versions < 0: raise ValueError( @@ -46,6 +50,7 @@ def __init__( self.max_staleness_versions = max_staleness_versions self.sample_freshest_first = sample_freshest_first self.require_order = require_order + self.force_in_order = force_in_order async def select( self, @@ -70,29 +75,38 @@ async def select( if min_prompt_groups < 1: raise ValueError(f"min_prompt_groups must be >= 1, got {min_prompt_groups}") - min_valid_version = max(0, current_train_weight - self.max_staleness_versions) - - if self.require_order: - in_window = [ - weight - for weight in self._buffer.start_weight_list - if min_valid_version <= weight <= current_train_weight - ] - if not in_window: - return None, 0 - target_version = min(in_window) + if self.force_in_order: + # target_step exact match; staleness window ignored. valid_idxs = [ i - for i, weight in enumerate(self._buffer.start_weight_list) - if weight == target_version and self._buffer.ready_list[i] + for i, target in enumerate(self._buffer.target_step_list) + if target == current_train_weight and self._buffer.ready_list[i] ] else: - valid_idxs = [ - i - for i, weight in enumerate(self._buffer.start_weight_list) - if min_valid_version <= weight <= current_train_weight - and self._buffer.ready_list[i] - ] + min_valid_version = max( + 0, current_train_weight - self.max_staleness_versions + ) + if self.require_order: + in_window = [ + weight + for weight in self._buffer.start_weight_list + if min_valid_version <= weight <= current_train_weight + ] + if not in_window: + return None, 0 + target_version = min(in_window) + valid_idxs = [ + i + for i, weight in enumerate(self._buffer.start_weight_list) + if weight == target_version and self._buffer.ready_list[i] + ] + else: + valid_idxs = [ + i + for i, weight in enumerate(self._buffer.start_weight_list) + if min_valid_version <= weight <= current_train_weight + and self._buffer.ready_list[i] + ] if len(valid_idxs) < min_prompt_groups: return None, 0 diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 23725f1f16a..bea3496fe25 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -36,7 +36,7 @@ import asyncio import time -from typing import Any, Union +from typing import Any, Optional, Union import ray import torch @@ -153,10 +153,17 @@ def __init__( f"({expected_buffer})" ) + if self._async_cfg.force_in_order and self._async_cfg.over_sampling: + raise ValueError( + "force_in_order=True requires over_sampling=False so that each " + "dispatched batch corresponds to exactly one target training step." + ) + self._sampler = StalenessSampler( self._buffer, max_staleness_versions=self._async_cfg.max_weight_staleness_versions, require_order=not self._async_cfg.over_sampling, + force_in_order=self._async_cfg.force_in_order, ) # ── asyncio state ────────────────────────────────────────────────── @@ -280,12 +287,17 @@ async def _rollout_pump(self) -> None: sem = asyncio.Semaphore(self._async_cfg.max_inflight_prompts) over_sampling = self._async_cfg.over_sampling max_staleness = self._async_cfg.max_weight_staleness_versions + force_in_order = self._async_cfg.force_in_order print("rollout_pump: starting", flush=True) - async def _dispatch_one_prompt(prompt: DatumSpec) -> None: + async def _dispatch_one_prompt( + prompt: DatumSpec, target_step: Optional[int] + ) -> None: self._inflight_rollouts += 1 try: - await self._rollout_manager.generate_and_push(prompt) + await self._rollout_manager.generate_and_push( + prompt, target_step=target_step + ) if self._diagnostics: content = "" for i in range(len(prompt["message_log"])): @@ -310,6 +322,9 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: await asyncio.sleep(0.005) self._max_rollout_version += 1 + # target_step = batch dispatch index when force_in_order is on. + target_step = self._max_rollout_version if force_in_order else None + for prompt_idx in range(prompt_batch.size): prompt: DatumSpec = { # type: ignore k: v[prompt_idx] for k, v in prompt_batch.items() @@ -323,7 +338,9 @@ async def _dispatch_one_prompt(prompt: DatumSpec) -> None: await self._rollout_permitted.wait() # dispatch rollout - task = asyncio.create_task(_dispatch_one_prompt(prompt)) + task = asyncio.create_task( + _dispatch_one_prompt(prompt, target_step) + ) self._dispatched_rollouts.add(task) task.add_done_callback(self._dispatched_rollouts.discard) epoch += 1 diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py index 53bd1aa0e1e..12138184d15 100644 --- a/nemo_rl/algorithms/single_controller_utils/config.py +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -45,6 +45,10 @@ class AsyncRLConfig(BaseModel, extra="allow"): # True : over-generates and wastes rollouts that age past the staleness window; # False: enforces per-weight-version dispatch quota. over_sampling: bool = True + # Tag rollouts with their dispatch-time target step and require an exact + # match at sample time (legacy target_weight semantics). Requires + # over_sampling=False. + force_in_order: bool = False class MasterConfig(BaseModel, extra="allow"): diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 83b9d09a72b..5802529e194 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -638,17 +638,22 @@ def set_weight_version(self, version: int) -> None: async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: return await self._impl.run_rollout(input_sample) - async def generate_and_push(self, input_sample: DatumSpec) -> None: + async def generate_and_push( + self, input_sample: DatumSpec, *, target_step: Optional[int] = None + ) -> None: """Reserve a buffer slot, run one prompt's rollout, then commit the slot. Args: input_sample: A single prompt (one DatumSpec entry). + target_step: Training step this rollout targets; stamped on the buffer slot for StalenessSampler.force_in_order. """ assert self._tq_buffer is not None, ( "generate_and_push requires tq_buffer to be set at __init__" ) start_version = self._weight_version - group_id = self._tq_buffer.reserve(weight_version=start_version) + group_id = self._tq_buffer.reserve( + weight_version=start_version, target_step=target_step + ) record = await self.run_rollout(input_sample) end_version = self._weight_version From bfb2467fe91e3c9329673b228e381994b1a136cc Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Mon, 22 Jun 2026 04:58:41 -0700 Subject: [PATCH 21/44] feat(sc): assert num_prompts * num_gen == train_global_batch_size Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index bea3496fe25..17865d47dfb 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -159,6 +159,23 @@ def __init__( "dispatched batch corresponds to exactly one target training step." ) + # SC split path does one optimizer.step per RL step. + # TODO: support multi-mini-step (legacy train() does gbs-sized + # mini-steps with shared prev_logprobs). + rl_step_samples = ( + self._master_config.grpo["num_prompts_per_step"] + * self._master_config.grpo["num_generations_per_prompt"] + ) + train_gbs = self._master_config.policy["train_global_batch_size"] + if rl_step_samples != train_gbs: + raise ValueError( + f"num_prompts_per_step * num_generations_per_prompt " + f"({rl_step_samples}) must equal policy.train_global_batch_size " + f"({train_gbs}) so that one RL step maps to exactly one " + f"optimizer.step. Multi-mini-step inside a single RL step is " + f"not supported on the SC split path." + ) + self._sampler = StalenessSampler( self._buffer, max_staleness_versions=self._async_cfg.max_weight_staleness_versions, From 2bc4b63ab6dd8d408e592966ddae8907e1e18250 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Mon, 22 Jun 2026 04:59:37 -0700 Subject: [PATCH 22/44] [tmp] upload yaml/script for debug Signed-off-by: Yuki Huang --- .../performance/grpo-llama3.1-8b-instruct-2n8g.yaml | 1 + ...1-8b-instruct-2n8g-async-1off-single-controller.sh | 8 ++++---- ...rpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v3.sh | 5 +++-- ...h-1.5b-instruct-1n8g-megatron-single-controller.sh | 2 +- .../grpo-llama3.1-8b-instruct-2n8g-async-1off.sh | 11 ++++++----- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/examples/configs/recipes/llm/performance/grpo-llama3.1-8b-instruct-2n8g.yaml b/examples/configs/recipes/llm/performance/grpo-llama3.1-8b-instruct-2n8g.yaml index d965796558b..6ffd52c96a3 100644 --- a/examples/configs/recipes/llm/performance/grpo-llama3.1-8b-instruct-2n8g.yaml +++ b/examples/configs/recipes/llm/performance/grpo-llama3.1-8b-instruct-2n8g.yaml @@ -11,6 +11,7 @@ policy: model_name: meta-llama/Llama-3.1-8B-Instruct tokenizer: name: meta-llama/Llama-3.1-8B-Instruct + train_global_batch_size: 2048 train_micro_batch_size: 1 logprob_batch_size: 2 max_total_sequence_length: 4096 diff --git a/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh b/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh index 7476f62fcfc..e4c254c78f2 100755 --- a/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh +++ b/tests/test_suites/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.sh @@ -4,10 +4,10 @@ source $SCRIPT_DIR/common.env # ===== BEGIN CONFIG ===== NUM_NODES=2 -STEPS_PER_RUN=10 -MAX_STEPS=10 +STEPS_PER_RUN=100 +MAX_STEPS=100 NUM_RUNS=$(( (MAX_STEPS + STEPS_PER_RUN - 1) / STEPS_PER_RUN )) # Round up -NUM_MINUTES=100 +NUM_MINUTES=240 # ===== END CONFIG ===== exit_if_max_steps_reached @@ -19,7 +19,7 @@ uv run examples/run_grpo_single_controller.py \ grpo.max_num_steps=$MAX_STEPS \ logger.log_dir=$LOG_DIR \ logger.wandb_enabled=True \ - logger.wandb.project=nemo-rl \ + logger.wandb.project=sc-yukih \ logger.wandb.name=$EXP_NAME \ logger.monitor_gpus=True \ logger.tensorboard_enabled=True \ diff --git a/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v3.sh b/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v3.sh index 353804958e5..298b6e0e9d3 100755 --- a/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v3.sh +++ b/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-fsdp2tp1.v3.sh @@ -17,13 +17,14 @@ cd $PROJECT_ROOT uv run examples/run_grpo.py \ --config $CONFIG_PATH \ grpo.max_num_steps=$MAX_STEPS \ + grpo.val_period=-1 \ logger.log_dir=$LOG_DIR \ logger.wandb_enabled=True \ - logger.wandb.project=nemo-rl \ + logger.wandb.project=sc-yukih \ logger.wandb.name=$EXP_NAME \ logger.monitor_gpus=True \ logger.tensorboard_enabled=True \ - checkpointing.enabled=True \ + checkpointing.enabled=false \ checkpointing.checkpoint_dir=$CKPT_DIR \ $@ \ 2>&1 | tee $RUN_LOG diff --git a/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh b/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh index 96b5758dfc2..978b8893ee5 100755 --- a/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh +++ b/tests/test_suites/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.sh @@ -19,7 +19,7 @@ uv run examples/run_grpo_single_controller.py \ grpo.max_num_steps=$MAX_STEPS \ logger.log_dir=$LOG_DIR \ logger.wandb_enabled=True \ - logger.wandb.project=nemo-rl \ + logger.wandb.project=sc-yukih \ logger.wandb.name=$EXP_NAME \ logger.monitor_gpus=True \ logger.tensorboard_enabled=True \ diff --git a/tests/test_suites/llm/performance/grpo-llama3.1-8b-instruct-2n8g-async-1off.sh b/tests/test_suites/llm/performance/grpo-llama3.1-8b-instruct-2n8g-async-1off.sh index f9f561e3dcc..0555651b0af 100755 --- a/tests/test_suites/llm/performance/grpo-llama3.1-8b-instruct-2n8g-async-1off.sh +++ b/tests/test_suites/llm/performance/grpo-llama3.1-8b-instruct-2n8g-async-1off.sh @@ -4,10 +4,10 @@ source $SCRIPT_DIR/common.env # ===== BEGIN CONFIG ===== NUM_NODES=2 -STEPS_PER_RUN=10 -MAX_STEPS=10 +STEPS_PER_RUN=100 +MAX_STEPS=100 NUM_RUNS=$(( (MAX_STEPS + STEPS_PER_RUN - 1) / STEPS_PER_RUN )) # Round up -NUM_MINUTES=100 +NUM_MINUTES=240 # ===== END CONFIG ===== exit_if_max_steps_reached @@ -17,13 +17,14 @@ cd $PROJECT_ROOT uv run examples/run_grpo.py \ --config $CONFIG_PATH \ grpo.max_num_steps=$MAX_STEPS \ + grpo.val_period=-1 \ logger.log_dir=$LOG_DIR \ logger.wandb_enabled=True \ - logger.wandb.project=nemo-rl \ + logger.wandb.project=sc-yukih \ logger.wandb.name=$EXP_NAME \ logger.monitor_gpus=True \ logger.tensorboard_enabled=True \ - checkpointing.enabled=True \ + checkpointing.enabled=false \ checkpointing.checkpoint_dir=$CKPT_DIR \ $@ \ 2>&1 | tee $RUN_LOG From 50de76f05214d1a94eb8c6b54ae16b9fc6da30e0 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 28 Jun 2026 01:57:57 -0700 Subject: [PATCH 23/44] refactor(sc): drop async_rl.target_prompt_groups_per_step, use grpo.num_prompts_per_step Signed-off-by: Yuki Huang --- .../grpo_math_1B_single_controller.yaml | 4 +-- ...uct-2n8g-async-1off-single-controller.yaml | 2 +- ...truct-1n8g-megatron-single-controller.yaml | 2 +- nemo_rl/algorithms/single_controller.py | 27 +++++++------------ .../single_controller_utils/config.py | 1 - tests/functional/grpo_dp_single_controller.sh | 1 - .../single_controller/test_rollout_pump.py | 1 - 7 files changed, 13 insertions(+), 25 deletions(-) diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml index 11736772e7d..d8a7c3b2782 100644 --- a/examples/configs/grpo_math_1B_single_controller.yaml +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -337,14 +337,14 @@ data_plane: local_buffer_size: 68719476736 # SC-specific async-RL runtime knobs. +# One training step consumes grpo.num_prompts_per_step prompt groups. async_rl: max_weight_staleness_versions: 1 min_prompt_groups_per_batch: 2 - target_prompt_groups_per_step: null # falls back to min_prompt_groups_per_batch batch_selection_strategy: "strict_on_policy" # or "staleness_window" max_inflight_prompts: 8 # When over_sampling=false this must equal - # target_prompt_groups_per_step * (max_weight_staleness_versions + 1). + # grpo.num_prompts_per_step * (max_weight_staleness_versions + 1). max_buffered_rollouts: 8 # True : over-generates and wastes rollouts that age past the staleness window; # False: enforces per-weight-version dispatch quota. diff --git a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml index 8e12944aec6..68b9cf3e6ca 100644 --- a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml @@ -26,7 +26,7 @@ async_rl: batch_selection_strategy: staleness_window max_inflight_prompts: ${grpo.num_prompts_per_step} # match grpo-llama3.1-8b-instruct-2n8g-async-1off # over_sampling=false requires - # max_buffered_rollouts == target_prompt_groups_per_step * (max_weight_staleness_versions + 1) + # max_buffered_rollouts == grpo.num_prompts_per_step * (max_weight_staleness_versions + 1) # 64 * (1 + 1) = 128 max_buffered_rollouts: 128 over_sampling: false diff --git a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml index eae1c00d09c..610e5489bf6 100644 --- a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml @@ -26,7 +26,7 @@ async_rl: max_inflight_prompts: 64 # strict_on_policy auto-sets max_weight_staleness_versions=0 and # over_sampling=False. over_sampling=false requires - # max_buffered_rollouts == target_prompt_groups_per_step * (max_weight_staleness_versions + 1) + # max_buffered_rollouts == grpo.num_prompts_per_step * (max_weight_staleness_versions + 1) # 32 * (0 + 1) = 32 max_buffered_rollouts: 32 over_sampling: false diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 17865d47dfb..19ea5defeff 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -120,17 +120,12 @@ def __init__( self._train_cluster = bundle.train_cluster self._inference_cluster = bundle.inference_cluster - if self._async_cfg.target_prompt_groups_per_step is None: - self._async_cfg.target_prompt_groups_per_step = ( - self._async_cfg.min_prompt_groups_per_batch - ) - if ( - self._async_cfg.target_prompt_groups_per_step - < self._async_cfg.min_prompt_groups_per_batch - ): + num_prompts_per_step = self._master_config.grpo["num_prompts_per_step"] + if num_prompts_per_step < self._async_cfg.min_prompt_groups_per_batch: raise ValueError( - f"target_prompt_groups_per_step ({self._async_cfg.target_prompt_groups_per_step}) " - f"must be >= min_prompt_groups_per_batch ({self._async_cfg.min_prompt_groups_per_batch})" + f"grpo.num_prompts_per_step ({num_prompts_per_step}) " + f"must be >= async_rl.min_prompt_groups_per_batch " + f"({self._async_cfg.min_prompt_groups_per_batch})" ) if self._async_cfg.batch_selection_strategy == "strict_on_policy": @@ -142,14 +137,14 @@ def __init__( ) if not self._async_cfg.over_sampling: - expected_buffer = self._async_cfg.target_prompt_groups_per_step * ( + expected_buffer = num_prompts_per_step * ( self._async_cfg.max_weight_staleness_versions + 1 ) if self._async_cfg.max_buffered_rollouts != expected_buffer: raise ValueError( f"over_sampling=False requires max_buffered_rollouts " f"({self._async_cfg.max_buffered_rollouts}) == " - f"target_prompt_groups_per_step * (max_weight_staleness_versions + 1) " + f"num_prompts_per_step * (max_weight_staleness_versions + 1) " f"({expected_buffer})" ) @@ -163,7 +158,7 @@ def __init__( # TODO: support multi-mini-step (legacy train() does gbs-sized # mini-steps with shared prev_logprobs). rl_step_samples = ( - self._master_config.grpo["num_prompts_per_step"] + num_prompts_per_step * self._master_config.grpo["num_generations_per_prompt"] ) train_gbs = self._master_config.policy["train_global_batch_size"] @@ -386,15 +381,11 @@ async def _train_pump(self) -> None: while self._train_steps < grpo_cfg["max_num_steps"]: step_id = f"sc-step-{self._train_steps:06d}" - # __init__ coerces None → min_prompt_groups_per_batch (int); - # the assert narrows the Optional[int] type for pyrefly. - assert self._async_cfg.target_prompt_groups_per_step is not None - target_groups: int = self._async_cfg.target_prompt_groups_per_step groups_dispatched = 0 step_open = False with self._timer.time("total_step_time"): - while groups_dispatched < target_groups: + while groups_dispatched < grpo_cfg["num_prompts_per_step"]: await asyncio.sleep(0) # evict stale groups diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py index 12138184d15..26bfb43c3d3 100644 --- a/nemo_rl/algorithms/single_controller_utils/config.py +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -34,7 +34,6 @@ class AsyncRLConfig(BaseModel, extra="allow"): # Sampler / on-policy enforcement. max_weight_staleness_versions: int = 1 min_prompt_groups_per_batch: int = 2 - target_prompt_groups_per_step: Optional[int] = None batch_selection_strategy: Literal[ "strict_on_policy", "staleness_window", diff --git a/tests/functional/grpo_dp_single_controller.sh b/tests/functional/grpo_dp_single_controller.sh index 8ec7fd83e26..5ed3dc95462 100755 --- a/tests/functional/grpo_dp_single_controller.sh +++ b/tests/functional/grpo_dp_single_controller.sh @@ -40,7 +40,6 @@ uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJE data_plane.impl=transfer_queue \ data_plane.backend=simple \ async_rl.min_prompt_groups_per_batch=2 \ - async_rl.target_prompt_groups_per_step=2 \ async_rl.batch_selection_strategy=strict_on_policy \ async_rl.max_inflight_prompts=4 \ async_rl.max_buffered_rollouts=4 \ diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index 3fcf9a3db43..04a923ecd82 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -185,7 +185,6 @@ def test_rollout_pump_writes_expected_tq_data( async_rl=AsyncRLConfig( max_weight_staleness_versions=0, min_prompt_groups_per_batch=1, - target_prompt_groups_per_step=None, batch_selection_strategy="strict_on_policy", max_inflight_prompts=max_rollout_prompts, max_buffered_rollouts=max_rollout_prompts, From c48c050b2d24e38698875118e41f05010b2f0560 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 28 Jun 2026 02:09:31 -0700 Subject: [PATCH 24/44] refactor(sc): move batch_selection_strategy to top of async_rl, fix functional test buffer sizing Signed-off-by: Yuki Huang --- examples/configs/grpo_math_1B_single_controller.yaml | 2 +- ....1-8b-instruct-2n8g-async-1off-single-controller.yaml | 2 +- ...th-1.5b-instruct-1n8g-megatron-single-controller.yaml | 2 +- nemo_rl/algorithms/single_controller_utils/config.py | 6 +++--- tests/functional/grpo_dp_single_controller.sh | 9 +++++---- tests/unit/single_controller/test_rollout_pump.py | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml index d8a7c3b2782..18df0835b41 100644 --- a/examples/configs/grpo_math_1B_single_controller.yaml +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -339,9 +339,9 @@ data_plane: # SC-specific async-RL runtime knobs. # One training step consumes grpo.num_prompts_per_step prompt groups. async_rl: + batch_selection_strategy: "strict_on_policy" # or "staleness_window" max_weight_staleness_versions: 1 min_prompt_groups_per_batch: 2 - batch_selection_strategy: "strict_on_policy" # or "staleness_window" max_inflight_prompts: 8 # When over_sampling=false this must equal # grpo.num_prompts_per_step * (max_weight_staleness_versions + 1). diff --git a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml index 68b9cf3e6ca..ee3f8b97acd 100644 --- a/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-llama3.1-8b-instruct-2n8g-async-1off-single-controller.yaml @@ -19,11 +19,11 @@ data_plane: # SC async-RL runtime knobs. async_rl: + batch_selection_strategy: staleness_window # Matches grpo.async_grpo.max_trajectory_age_steps=1. max_weight_staleness_versions: 1 # One training step consumes grpo.num_prompts_per_step (=64) prompt groups. min_prompt_groups_per_batch: 64 - batch_selection_strategy: staleness_window max_inflight_prompts: ${grpo.num_prompts_per_step} # match grpo-llama3.1-8b-instruct-2n8g-async-1off # over_sampling=false requires # max_buffered_rollouts == grpo.num_prompts_per_step * (max_weight_staleness_versions + 1) diff --git a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml index 610e5489bf6..949bd31f11b 100644 --- a/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml +++ b/examples/configs/recipes/llm/grpo-qwen2.5-math-1.5b-instruct-1n8g-megatron-single-controller.yaml @@ -20,9 +20,9 @@ data_plane: # SC async-RL runtime knobs. async_rl: + batch_selection_strategy: strict_on_policy # One training step consumes grpo.num_prompts_per_step (=32) prompt groups. min_prompt_groups_per_batch: 32 - batch_selection_strategy: strict_on_policy max_inflight_prompts: 64 # strict_on_policy auto-sets max_weight_staleness_versions=0 and # over_sampling=False. over_sampling=false requires diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py index 26bfb43c3d3..9ffa122adc5 100644 --- a/nemo_rl/algorithms/single_controller_utils/config.py +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -31,13 +31,13 @@ class AsyncRLConfig(BaseModel, extra="allow"): - # Sampler / on-policy enforcement. - max_weight_staleness_versions: int = 1 - min_prompt_groups_per_batch: int = 2 batch_selection_strategy: Literal[ "strict_on_policy", "staleness_window", ] = "strict_on_policy" + # Sampler / on-policy enforcement. + max_weight_staleness_versions: int = 1 + min_prompt_groups_per_batch: int = 2 # Pump concurrency caps. max_inflight_prompts: int = 8 max_buffered_rollouts: int = 8 diff --git a/tests/functional/grpo_dp_single_controller.sh b/tests/functional/grpo_dp_single_controller.sh index 5ed3dc95462..abd590cc470 100755 --- a/tests/functional/grpo_dp_single_controller.sh +++ b/tests/functional/grpo_dp_single_controller.sh @@ -27,7 +27,7 @@ uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJE policy.model_name=Qwen/Qwen3-0.6B \ grpo.num_prompts_per_step=2 \ grpo.num_generations_per_prompt=4 \ - policy.train_global_batch_size=4 \ + policy.train_global_batch_size=8 \ policy.train_micro_batch_size=1 \ cluster.gpus_per_node=2 \ grpo.max_num_steps=2 \ @@ -39,10 +39,11 @@ uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJE data_plane.enabled=true \ data_plane.impl=transfer_queue \ data_plane.backend=simple \ - async_rl.min_prompt_groups_per_batch=2 \ async_rl.batch_selection_strategy=strict_on_policy \ - async_rl.max_inflight_prompts=4 \ - async_rl.max_buffered_rollouts=4 \ + async_rl.max_weight_staleness_versions=0 \ + async_rl.min_prompt_groups_per_batch=2 \ + async_rl.max_inflight_prompts=2 \ + async_rl.max_buffered_rollouts=2 \ $@ \ 2>&1 | tee $RUN_LOG diff --git a/tests/unit/single_controller/test_rollout_pump.py b/tests/unit/single_controller/test_rollout_pump.py index 04a923ecd82..b4d5f291b3d 100644 --- a/tests/unit/single_controller/test_rollout_pump.py +++ b/tests/unit/single_controller/test_rollout_pump.py @@ -183,9 +183,9 @@ def test_rollout_pump_writes_expected_tq_data( "num_generations_per_prompt": num_generations, }, async_rl=AsyncRLConfig( + batch_selection_strategy="strict_on_policy", max_weight_staleness_versions=0, min_prompt_groups_per_batch=1, - batch_selection_strategy="strict_on_policy", max_inflight_prompts=max_rollout_prompts, max_buffered_rollouts=max_rollout_prompts, ), From 1e0107e35def4c02a34975007e2d47d1ceaffe46 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 28 Jun 2026 04:20:43 -0700 Subject: [PATCH 25/44] fix rebase Signed-off-by: Yuki Huang --- examples/configs/grpo_math_1B_single_controller.yaml | 1 + nemo_rl/algorithms/single_controller.py | 2 +- nemo_rl/algorithms/single_controller_utils/setup.py | 2 +- tests/unit/experience/test_rollouts.py | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml index 18df0835b41..b20eb9dc9fa 100644 --- a/examples/configs/grpo_math_1B_single_controller.yaml +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -147,6 +147,7 @@ policy: moe_token_dispatcher_type: "alltoall" moe_shared_expert_overlap: false gradient_accumulation_fusion: false + use_fused_weighted_squared_relu: false peft: enabled: false target_modules: [] diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 19ea5defeff..52f06209579 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -57,7 +57,7 @@ ) from nemo_rl.data.interfaces import DatumSpec from nemo_rl.data_plane import KVBatchMeta -from nemo_rl.models.generation.sglang import SGLangGeneration +from nemo_rl.models.generation.sglang.sglang_generation import SGLangGeneration from nemo_rl.models.generation.vllm import VllmGeneration from nemo_rl.models.policy.tq_policy import TQPolicy from nemo_rl.utils.logger import Logger diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index 07431e4d750..5a5ebde1419 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -41,7 +41,7 @@ from nemo_rl.distributed.virtual_cluster import RayVirtualCluster from nemo_rl.environments.interfaces import EnvironmentInterface from nemo_rl.experience.rollout_manager import RolloutManager -from nemo_rl.models.generation.sglang import SGLangGeneration +from nemo_rl.models.generation.sglang.sglang_generation import SGLangGeneration from nemo_rl.models.generation.vllm import VllmGeneration from nemo_rl.models.policy.tq_policy import TQPolicy from nemo_rl.weight_sync import WeightSynchronizer, create_weight_synchronizer diff --git a/tests/unit/experience/test_rollouts.py b/tests/unit/experience/test_rollouts.py index 95fb940cbcc..91cf854cde9 100644 --- a/tests/unit/experience/test_rollouts.py +++ b/tests/unit/experience/test_rollouts.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio import gc import json import tempfile From 2c50b8eda23b51f1bb3644dd75a85431e2454247 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 28 Jun 2026 08:06:15 -0700 Subject: [PATCH 26/44] feat(sc): wire NeMo-Gym rollouts into SingleController Signed-off-by: Yuki Huang --- .../nemo_gym/run_distillation_nemo_gym.py | 4 +- examples/nemo_gym/run_grpo_nemo_gym.py | 4 +- examples/run_grpo_single_controller.py | 17 +++ nemo_rl/algorithms/grpo.py | 59 +-------- .../single_controller_utils/setup.py | 35 +++++- nemo_rl/environments/nemo_gym.py | 62 +++++++++- nemo_rl/experience/rollout_manager.py | 23 ++-- .../grpo_async_gym_single_controller.sh | 112 ++++++++++++++++++ 8 files changed, 237 insertions(+), 79 deletions(-) create mode 100755 tests/functional/grpo_async_gym_single_controller.sh diff --git a/examples/nemo_gym/run_distillation_nemo_gym.py b/examples/nemo_gym/run_distillation_nemo_gym.py index 7af1e4de6d7..1fdcab6c68f 100644 --- a/examples/nemo_gym/run_distillation_nemo_gym.py +++ b/examples/nemo_gym/run_distillation_nemo_gym.py @@ -32,9 +32,7 @@ from nemo_rl.algorithms.utils import get_tokenizer from nemo_rl.data.utils import setup_response_data from nemo_rl.distributed.virtual_cluster import init_ray -from nemo_rl.environments.nemo_gym import ( - setup_nemo_gym_config, -) +from nemo_rl.environments.nemo_gym import setup_nemo_gym_config from nemo_rl.models.generation import configure_generation_config from nemo_rl.utils.config import ( load_config, diff --git a/examples/nemo_gym/run_grpo_nemo_gym.py b/examples/nemo_gym/run_grpo_nemo_gym.py index 25a2c184934..2557348a342 100644 --- a/examples/nemo_gym/run_grpo_nemo_gym.py +++ b/examples/nemo_gym/run_grpo_nemo_gym.py @@ -40,9 +40,7 @@ from nemo_rl.algorithms.utils import get_tokenizer from nemo_rl.data.utils import setup_response_data from nemo_rl.distributed.virtual_cluster import init_ray -from nemo_rl.environments.nemo_gym import ( - setup_nemo_gym_config, -) +from nemo_rl.environments.nemo_gym import setup_nemo_gym_config from nemo_rl.experience.rollouts import run_async_nemo_gym_rollout from nemo_rl.models.generation import configure_generation_config from nemo_rl.utils.config import ( diff --git a/examples/run_grpo_single_controller.py b/examples/run_grpo_single_controller.py index 7fa3a854321..bda2fe54999 100644 --- a/examples/run_grpo_single_controller.py +++ b/examples/run_grpo_single_controller.py @@ -22,6 +22,7 @@ import argparse import os import pprint +import sys import ray from omegaconf import OmegaConf @@ -33,6 +34,7 @@ ) from nemo_rl.algorithms.utils import get_tokenizer from nemo_rl.distributed.virtual_cluster import init_ray +from nemo_rl.environments.nemo_gym import setup_nemo_gym_config from nemo_rl.models.generation import configure_generation_config from nemo_rl.utils.config import ( load_config, @@ -41,6 +43,12 @@ ) from nemo_rl.utils.logger import get_next_experiment_dir +# Drop examples/ from sys.path so examples/nemo_gym/ (no __init__.py) doesn't +# shadow the real nemo_gym package as a namespace package. +current_dir = os.path.dirname(os.path.abspath(__file__)) +while current_dir in sys.path: + sys.path.remove(current_dir) + def parse_args() -> tuple[argparse.Namespace, list[str]]: """Parse command line arguments.""" @@ -107,6 +115,10 @@ def main() -> None: has_refit_draft_weights=has_refit_draft_weights, ) + # NeMo-Gym specific config setup. + if bool(config.env.get("should_use_nemo_gym")): + setup_nemo_gym_config(config, tokenizer) + bundle = setup_single_controller(config, tokenizer) print("🚀 Launching SingleControllerActor") @@ -114,6 +126,11 @@ def main() -> None: result = ray.get(sc.run.remote()) print(f"SC run complete: {result}") + # Drain env actors before vLLM shutdown to avoid race-condition 500s on + # in-flight requests. + for handle in bundle.env_handles.values(): + ray.get(handle.shutdown.remote()) + if __name__ == "__main__": main() diff --git a/nemo_rl/algorithms/grpo.py b/nemo_rl/algorithms/grpo.py index 5435df757a9..0d6453a6e7b 100644 --- a/nemo_rl/algorithms/grpo.py +++ b/nemo_rl/algorithms/grpo.py @@ -23,7 +23,6 @@ import ray import torch from pydantic import BaseModel -from ray.util.scheduling_strategies import NodeAffinitySchedulingStrategy from torchdata.stateful_dataloader import StatefulDataLoader from transformers import AutoProcessor from transformers.tokenization_utils_base import PreTrainedTokenizerBase @@ -74,12 +73,7 @@ prepare_segment_topology, ) from nemo_rl.environments.interfaces import EnvironmentInterface -from nemo_rl.environments.nemo_gym import ( - NemoGym, - NemoGymConfig, - get_nemo_gym_uv_cache_dir, - get_nemo_gym_venv_dir, -) +from nemo_rl.environments.nemo_gym import spinup_nemo_gym_actor from nemo_rl.experience.rollouts import ( EffortLevelsConfig, run_async_multi_turn_rollout, @@ -460,60 +454,11 @@ def init_train_dataloader(dataset, suffix: str = ""): # spinup can overlap with vLLM model loading via deferred model load. enable_nemo_gym = _should_use_nemo_gym(master_config) nemo_gym_actor = None - if enable_nemo_gym: - nemo_gym_num_nodes = env_configs.get("nemo_gym", {}).get("num_gpu_nodes", 0) - ray_runtime_ctx = ray.get_runtime_context() - ray_cur_node_id = ray_runtime_ctx.get_node_id() - else: - nemo_gym_num_nodes = 0 - ray_cur_node_id = None def _spinup_nemo_gym(base_urls, model_name): """Spin up the NeMo Gym actor against the given generation server URLs.""" t0 = time.perf_counter() - nemo_gym_py_exec = get_actor_python_env("nemo_rl.environments.nemo_gym.NemoGym") - if nemo_gym_py_exec.startswith("uv"): - nemo_gym_py_exec = create_local_venv_on_each_node( - nemo_gym_py_exec, "nemo_rl.environments.nemo_gym.NemoGym" - ) - nemo_gym_dict = env_configs["nemo_gym"] - # NeMo-RL-side detection knobs are top-level NemoGymConfig fields - # (where the detector reads them), not part of Gym's global config. - invalid_tool_call_patterns = nemo_gym_dict.pop( - "invalid_tool_call_patterns", None - ) - thinking_tags = nemo_gym_dict.pop("thinking_tags", None) - # Pass prebuilt cache + venv dirs through the global config so the gym reuses - # image-baked venvs instead of rebuilding them. - uv_cache_dir = get_nemo_gym_uv_cache_dir() - if uv_cache_dir is not None: - nemo_gym_dict.setdefault("uv_cache_dir", uv_cache_dir) - uv_venv_dir = get_nemo_gym_venv_dir() - if uv_venv_dir is not None: - nemo_gym_dict.setdefault("uv_venv_dir", uv_venv_dir) - nemo_gym_cfg = NemoGymConfig( - model_name=model_name, - base_urls=base_urls, - invalid_tool_call_patterns=invalid_tool_call_patterns, - thinking_tags=thinking_tags, - initial_global_config_dict=nemo_gym_dict, - ) - nemo_gym_opts = {} - if nemo_gym_num_nodes: - nemo_gym_opts["scheduling_strategy"] = NodeAffinitySchedulingStrategy( - node_id=ray_cur_node_id, - soft=True, - ) - nemo_gym_opts["runtime_env"] = { - "py_executable": nemo_gym_py_exec, - "env_vars": { - **os.environ, - "VIRTUAL_ENV": nemo_gym_py_exec, - "UV_PROJECT_ENVIRONMENT": nemo_gym_py_exec, - }, - } - actor = NemoGym.options(**nemo_gym_opts).remote(nemo_gym_cfg) - ray.get(actor._spinup.remote()) + actor = spinup_nemo_gym_actor(env_configs, base_urls, model_name) return actor, time.perf_counter() - t0 total_nodes = cluster_config["num_nodes"] diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index 5a5ebde1419..abae6882c64 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -30,7 +30,7 @@ from transformers.tokenization_utils_base import PreTrainedTokenizerBase from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer -from nemo_rl.algorithms.grpo import _create_advantage_estimator +from nemo_rl.algorithms.grpo import _create_advantage_estimator, _should_use_nemo_gym from nemo_rl.algorithms.loss import ClippedPGLossFn from nemo_rl.algorithms.loss.interfaces import LossFunction from nemo_rl.algorithms.single_controller_utils.config import MasterConfig @@ -40,6 +40,7 @@ from nemo_rl.data_plane import build_data_plane_client from nemo_rl.distributed.virtual_cluster import RayVirtualCluster from nemo_rl.environments.interfaces import EnvironmentInterface +from nemo_rl.environments.nemo_gym import spinup_nemo_gym_actor from nemo_rl.experience.rollout_manager import RolloutManager from nemo_rl.models.generation.sglang.sglang_generation import SGLangGeneration from nemo_rl.models.generation.vllm import VllmGeneration @@ -281,9 +282,18 @@ def setup_single_controller( # Setup Dataset & Environments # ========================== # TODO: add validate dataset wiring. - dataset, _val_dataset, env_handles, _val_env_handles = setup_response_data( - tokenizer, data_config, env_configs=master_config.env - ) + use_nemo_gym = _should_use_nemo_gym(master_config) + if use_nemo_gym: + # NeMo-Gym creates the env actor outside setup_response_data; we wire + # it in after generation is up (it needs the OpenAI server URLs). + dataset, _val_dataset = setup_response_data( + tokenizer, data_config, env_configs=None + ) + env_handles: dict[str, EnvironmentInterface] = {} + else: + dataset, _val_dataset, env_handles, _val_env_handles = setup_response_data( + tokenizer, data_config, env_configs=master_config.env + ) dataloader = StatefulDataLoader( dataset, batch_size=grpo_config["num_prompts_per_step"], @@ -319,6 +329,21 @@ def setup_single_controller( generation = gen_future.result() policy = policy_future.result() + # ========================== + # NeMo-Gym actor (after generation is up so OpenAI URLs are available) + # ========================== + if use_nemo_gym: + if generation_config["backend"] != "vllm": + raise NotImplementedError( + "SC NeMo-Gym integration currently supports the vllm backend " + f"only; got {generation_config['backend']!r}" + ) + env_handles["nemo_gym"] = spinup_nemo_gym_actor( + env_configs=master_config.env, + base_urls=generation.dp_openai_server_base_urls, + model_name=generation_config["model_name"], + ) + # ========================== # Setup Data Plane Client & Weight Sync # ========================== @@ -356,7 +381,7 @@ def setup_single_controller( max_rollout_turns=grpo_config.get("max_rollout_turns"), policy_generation=generation, generation_config=generation_config, - use_nemo_gym=False, + use_nemo_gym=use_nemo_gym, tq_buffer=tq_buffer, ) diff --git a/nemo_rl/environments/nemo_gym.py b/nemo_rl/environments/nemo_gym.py index 611751af362..15f511da88b 100644 --- a/nemo_rl/environments/nemo_gym.py +++ b/nemo_rl/environments/nemo_gym.py @@ -14,12 +14,14 @@ import os import subprocess from pathlib import Path -from typing import Any, Dict, List, NotRequired, TypedDict +from typing import Any, Dict, List, NotRequired, Optional, TypedDict import ray import torch +from ray.util.scheduling_strategies import NodeAffinitySchedulingStrategy from transformers import PreTrainedTokenizerBase +from nemo_rl.distributed.ray_actor_environment_registry import get_actor_python_env from nemo_rl.distributed.virtual_cluster import ( DEFAULT_GYM_PORT_RANGE_HIGH, DEFAULT_GYM_PORT_RANGE_LOW, @@ -28,6 +30,7 @@ ) from nemo_rl.environments.interfaces import EnvironmentInterface from nemo_rl.utils.timer import Timer +from nemo_rl.utils.venvs import create_local_venv_on_each_node DEFAULT_INVALID_TOOL_CALL_PATTERNS = [ "", @@ -445,3 +448,60 @@ def setup_nemo_gym_config(config, tokenizer) -> None: # Stop strings or token ids are not supported generation_config["stop_strings"] = None generation_config["stop_token_ids"] = None + + +def spinup_nemo_gym_actor( + env_configs: dict[str, Any], + base_urls: list[Optional[str]], + model_name: str, +) -> Any: + """Spin up the NeMo-Gym actor against the given generation server URLs. + + When ``env_configs["nemo_gym"]["num_gpu_nodes"] > 0``, the actor is + scheduled with soft NodeAffinity to the current Ray node so its colocated + GPU resources land where the caller expects. + """ + nemo_gym_py_exec = get_actor_python_env("nemo_rl.environments.nemo_gym.NemoGym") + if nemo_gym_py_exec.startswith("uv"): + nemo_gym_py_exec = create_local_venv_on_each_node( + nemo_gym_py_exec, "nemo_rl.environments.nemo_gym.NemoGym" + ) + + nemo_gym_dict = env_configs["nemo_gym"] + # NeMo-RL-side detection knobs are top-level NemoGymConfig fields + # (where the detector reads them), not part of Gym's global config. + invalid_tool_call_patterns = nemo_gym_dict.pop("invalid_tool_call_patterns", None) + thinking_tags = nemo_gym_dict.pop("thinking_tags", None) + uv_cache_dir = get_nemo_gym_uv_cache_dir() + if uv_cache_dir is not None: + nemo_gym_dict.setdefault("uv_cache_dir", uv_cache_dir) + uv_venv_dir = get_nemo_gym_venv_dir() + if uv_venv_dir is not None: + nemo_gym_dict.setdefault("uv_venv_dir", uv_venv_dir) + + nemo_gym_cfg = NemoGymConfig( + model_name=model_name, + base_urls=base_urls, + invalid_tool_call_patterns=invalid_tool_call_patterns, + thinking_tags=thinking_tags, + initial_global_config_dict=nemo_gym_dict, + ) + + nemo_gym_opts: dict[str, Any] = {} + if nemo_gym_dict.get("num_gpu_nodes", 0): + nemo_gym_opts["scheduling_strategy"] = NodeAffinitySchedulingStrategy( + node_id=ray.get_runtime_context().get_node_id(), + soft=True, + ) + nemo_gym_opts["runtime_env"] = { + "py_executable": nemo_gym_py_exec, + "env_vars": { + **os.environ, + "VIRTUAL_ENV": nemo_gym_py_exec, + "UV_PROJECT_ENVIRONMENT": nemo_gym_py_exec, + }, + } + + actor = NemoGym.options(**nemo_gym_opts).remote(nemo_gym_cfg) + ray.get(actor._spinup.remote()) + return actor diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 5802529e194..f382ab7af18 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -22,7 +22,7 @@ from wandb import Table from nemo_rl.algorithms.async_utils.replay_buffer import TQReplayBuffer -from nemo_rl.data.interfaces import DatumSpec +from nemo_rl.data.interfaces import DatumSpec, LLMMessageLogType from nemo_rl.distributed.batched_data_dict import BatchedDataDict from nemo_rl.environments.interfaces import EnvironmentInterface from nemo_rl.experience.interfaces import Completion, PromptGroupRecord @@ -392,7 +392,7 @@ def __init__( num_generations_per_prompt: int, max_seq_len: int, generation_config: GenerationConfig, - max_rollout_turns: Optional[int] = None, + max_rollout_turns: int, **kwargs: Any, ) -> None: self._tokenizer = tokenizer @@ -418,7 +418,7 @@ async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: timer.start(f"{timer_prefix}/total") rollout_inputs = self._build_inputs(input_sample) - completions, rollout_metrics = await self._run_rollouts( + completions, prompt_message_log, rollout_metrics = await self._run_rollouts( rollout_inputs, timer, timer_prefix ) @@ -427,7 +427,7 @@ async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: return PromptGroupRecord( prompt_idx=input_sample["idx"], - prompt=input_sample["message_log"], + prompt=prompt_message_log, extra_env_info=input_sample["extra_env_info"], metadata={"task_name": "nemo_gym"}, completions=completions, @@ -443,8 +443,9 @@ def _validate_init_params(self) -> None: ) # Validate max_rollout_turns. - assert self._max_rollout_turns is None, ( - "`max_rollout_turns` is not supported in NeMo-Gym path!" + assert self._max_rollout_turns == 1, ( + "`max_rollout_turns` is not supported in NeMo-Gym path! " + "Please set `max_rollout_turns` to 1." ) def _build_inputs(self, input_sample: DatumSpec) -> list[dict]: @@ -477,8 +478,8 @@ def _build_inputs(self, input_sample: DatumSpec) -> list[dict]: async def _run_rollouts( self, inputs: list[dict], timer: Timer, timer_prefix: str - ) -> tuple[list[Completion], dict[str, Any]]: - """Dispatch rows to NeMo-Gym and return completions + metrics.""" + ) -> tuple[list[Completion], LLMMessageLogType, dict[str, Any]]: + """Dispatch rows to NeMo-Gym; return completions, prompt, and metrics.""" nemo_gym_env = self._env_handles["nemo_gym"] # Run generation. @@ -486,6 +487,9 @@ async def _run_rollouts( results, env_timing_metrics = await nemo_gym_env.run_rollouts.remote( inputs, self._tokenizer, timer_prefix ) + # All N rollouts share the same input prompt; tensorize one copy. + prompt_message_log = results[0]["input_message_log"] + _tensorize_by_key(prompt_message_log, "token_ids") # Convert results to completions. completions = [self._result_to_completion(r) for r in results] @@ -497,12 +501,11 @@ async def _run_rollouts( rollout_metrics.update(env_timing_metrics) - return completions, rollout_metrics + return completions, prompt_message_log, rollout_metrics def _result_to_completion(self, result: dict) -> Completion: """Convert one run_rollouts result dict into a Completion.""" # Tensorize token fields. - _tensorize_by_key(result["input_message_log"], "token_ids") _tensorize_by_key(result["message_log"], "token_ids") _tensorize_by_key( [m for m in result["message_log"] if m["role"] == "assistant"], diff --git a/tests/functional/grpo_async_gym_single_controller.sh b/tests/functional/grpo_async_gym_single_controller.sh new file mode 100755 index 00000000000..f4f283bfffd --- /dev/null +++ b/tests/functional/grpo_async_gym_single_controller.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# SingleController + NeMo-Gym e2e smoke. Mirrors grpo_async_gym.sh but +# routes everything through the SC path (TransferQueue data plane + +# SingleControllerActor) instead of async_grpo_train. + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +PROJECT_ROOT=$(realpath $SCRIPT_DIR/../..) +# Mark the current repo as safe, since wandb fetches metadata about the repo +git config --global --add safe.directory $PROJECT_ROOT + +set -eou pipefail + +EXP_NAME=$(basename $0 .sh) +EXP_DIR=$SCRIPT_DIR/$EXP_NAME +LOG_DIR=$EXP_DIR/logs +JSON_METRICS=$EXP_DIR/metrics.json +RUN_LOG=$EXP_DIR/run.log +CHECKPOINT_DIR=$EXP_DIR/checkpoints +DATA_DIR=$EXP_DIR/data +export PYTHONPATH=${PROJECT_ROOT}:${PYTHONPATH:-} + +rm -rf $EXP_DIR $LOG_DIR +mkdir -p $EXP_DIR $LOG_DIR $CHECKPOINT_DIR $DATA_DIR + +# clean up checkpoint directory on exit +trap "rm -rf $CHECKPOINT_DIR" EXIT + +cd $PROJECT_ROOT + +# Follow nemo-gym instructions here to get this data: +# https://docs.nvidia.com/nemo/gym/0.1.0/tutorials/nemo-rl-grpo/setup.html#training-nemo-rl-grpo-setup +cd 3rdparty/Gym-workspace/Gym + +# We need HF_TOKEN to download the data from huggingface +if [[ ! -f env.yaml ]]; then + if [[ -z "${HF_TOKEN:-}" ]]; then + echo "[ERROR] HF_TOKEN is not set" + exit 1 + fi + echo "hf_token: $HF_TOKEN" >> env.yaml +fi + +uv run ng_prepare_data "+config_paths=[resources_servers/workplace_assistant/configs/workplace_assistant.yaml]" \ + +output_dirpath=data/workplace_assistant \ + +mode=train_preparation \ + +should_download=true \ + +data_source=huggingface +cd - + +# This trimming of the workplace assistant dataset is necessary b/c with all the tools the first prompt is >4000 tokens +# which will cause vllm to return nothing on the first prompt and crash RL. Since we want to keep this test short to +# smoke test, we trim all but the first tool +TRAIN_PATH=$DATA_DIR/workplace_assistant_train.jsonl +VALIDATION_PATH=$DATA_DIR/workplace_assistant_validation.jsonl +jq -c '.responses_create_params.tools |= (.[0:1])' 3rdparty/Gym-workspace/Gym/data/workplace_assistant/train.jsonl > $TRAIN_PATH +jq -c '.responses_create_params.tools |= (.[0:1])' 3rdparty/Gym-workspace/Gym/data/workplace_assistant/validation.jsonl > $VALIDATION_PATH + +uv run coverage run -a --data-file=$PROJECT_ROOT/tests/.coverage --source=$PROJECT_ROOT/nemo_rl \ + $PROJECT_ROOT/examples/run_grpo_single_controller.py \ + --config $PROJECT_ROOT/examples/nemo_gym/grpo_qwen3_30ba3b_instruct.yaml \ + policy.model_name=Qwen/Qwen3-0.6B \ + policy.dtensor_cfg.enabled=false \ + policy.megatron_cfg.enabled=true \ + policy.megatron_cfg.tensor_model_parallel_size=1 \ + policy.megatron_cfg.pipeline_model_parallel_size=1 \ + policy.megatron_cfg.expert_model_parallel_size=1 \ + policy.megatron_cfg.context_parallel_size=1 \ + policy.megatron_cfg.sequence_parallel=false \ + policy.generation.vllm_cfg.tensor_parallel_size=1 \ + policy.generation.vllm_cfg.async_engine=true \ + policy.max_total_sequence_length=512 \ + policy.generation.colocated.enabled=false \ + policy.generation.colocated.resources.num_nodes=1 \ + policy.generation.colocated.resources.gpus_per_node=1 \ + grpo.num_prompts_per_step=4 \ + grpo.num_generations_per_prompt=2 \ + grpo.max_num_steps=10 \ + grpo.val_period=-1 \ + policy.train_global_batch_size=8 \ + policy.train_micro_batch_size=1 \ + cluster.gpus_per_node=2 \ + loss_fn.reference_policy_kl_penalty=0.01 \ + loss_fn.use_importance_sampling_correction=true \ + logger.tensorboard_enabled=true \ + logger.log_dir=$LOG_DIR \ + logger.wandb_enabled=false \ + logger.monitor_gpus=true \ + checkpointing.enabled=false \ + data.train.data_path=$TRAIN_PATH \ + data.validation.data_path=$VALIDATION_PATH \ + ++data_plane.enabled=true \ + ++data_plane.impl=transfer_queue \ + ++data_plane.backend=simple \ + ++data_plane.storage_capacity=1000000 \ + ++data_plane.num_storage_units=2 \ + ++data_plane.claim_meta_poll_interval_s=0.5 \ + ++data_plane.global_segment_size=549755813888 \ + ++data_plane.local_buffer_size=68719476736 \ + ++async_rl.batch_selection_strategy=strict_on_policy \ + ++async_rl.max_weight_staleness_versions=0 \ + ++async_rl.min_prompt_groups_per_batch=4 \ + ++async_rl.max_inflight_prompts=4 \ + ++async_rl.max_buffered_rollouts=4 \ + $@ \ + 2>&1 | tee $RUN_LOG + +uv run tests/json_dump_tb_logs.py $LOG_DIR --output_path $JSON_METRICS + +# Observed to be between 0.8-1.3 +uv run tests/check_metrics.py $JSON_METRICS \ + 'median(data["train/gen_kl_error"]) < 1.3' \ + 'max(data["train/reward"]) > 0' From c4347ce7b98462333b0aa1476b2ca3982ea5918b Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Sun, 28 Jun 2026 08:11:52 -0700 Subject: [PATCH 27/44] ci: add L1_Functional_Tests_SingleController; move grpo_dp_single_controller and grpo_async_gym_single_controller into it Signed-off-by: Yuki Huang --- .github/workflows/cicd-main.yml | 6 +++ .../functional/L1_Functional_Tests_GRPO_3.sh | 1 - .../L1_Functional_Tests_SingleController.sh | 43 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100755 tests/functional/L1_Functional_Tests_SingleController.sh diff --git a/.github/workflows/cicd-main.yml b/.github/workflows/cicd-main.yml index c96de48db50..c8ff05e1e29 100644 --- a/.github/workflows/cicd-main.yml +++ b/.github/workflows/cicd-main.yml @@ -717,6 +717,8 @@ jobs: runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} - script: L1_Functional_Tests_PPO runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} + - script: L1_Functional_Tests_SingleController + runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} - script: L1_Functional_Tests_Eval runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} - script: L1_Functional_Tests_Other_1 @@ -786,6 +788,8 @@ jobs: runner: ${{ vars.GB200_RUNNER }} - script: L1_Functional_Tests_PPO runner: ${{ vars.GB200_RUNNER }} + - script: L1_Functional_Tests_SingleController + runner: ${{ vars.GB200_RUNNER }} - script: L1_Functional_Tests_Eval runner: ${{ vars.GB200_RUNNER }} - script: L1_Functional_Tests_Other_1 @@ -856,6 +860,8 @@ jobs: runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} - script: L1_Functional_Tests_PPO runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} + - script: L1_Functional_Tests_SingleController + runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} - script: L1_Functional_Tests_Eval runner: ${{ needs.org-member-pre-flight.outputs.runner_prefix }} - script: L1_Functional_Tests_Other_1 diff --git a/tests/functional/L1_Functional_Tests_GRPO_3.sh b/tests/functional/L1_Functional_Tests_GRPO_3.sh index 004194b4b6a..cb858eb4387 100644 --- a/tests/functional/L1_Functional_Tests_GRPO_3.sh +++ b/tests/functional/L1_Functional_Tests_GRPO_3.sh @@ -37,7 +37,6 @@ run_test() { run_test uv run --no-sync bash ./tests/functional/grpo_rm_env.sh run_test fast uv run --no-sync bash ./tests/functional/grpo_topp_topk.sh run_test uv run --no-sync bash ./tests/functional/vlm_grpo.sh -run_test fast uv run --no-sync bash ./tests/functional/grpo_dp_single_controller.sh cd ${PROJECT_ROOT}/tests if compgen -G ".coverage*" > /dev/null; then diff --git a/tests/functional/L1_Functional_Tests_SingleController.sh b/tests/functional/L1_Functional_Tests_SingleController.sh new file mode 100755 index 00000000000..2a6fad63eea --- /dev/null +++ b/tests/functional/L1_Functional_Tests_SingleController.sh @@ -0,0 +1,43 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +#!/bin/bash +set -xeuo pipefail # Exit immediately if a command exits with a non-zero status + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +PROJECT_ROOT=$(realpath ${SCRIPT_DIR}/../..) + +cd ${PROJECT_ROOT} + +# run_test [fast] +# - "run_test fast " = always runs (both fast and full modes) +# - "run_test " = only runs in full mode; skipped when FAST=1 +run_test() { + if [[ "$1" == "fast" ]]; then + shift + time "$@" + elif [[ "${FAST:-0}" == "1" ]]; then + echo "FAST: Skipping: $*" + else + time "$@" + fi +} + +run_test fast uv run --no-sync bash ./tests/functional/grpo_dp_single_controller.sh +run_test fast uv run --no-sync bash ./tests/functional/grpo_async_gym_single_controller.sh + +cd ${PROJECT_ROOT}/tests +if compgen -G ".coverage*" > /dev/null; then + coverage combine .coverage* +fi From 42f66e32fc804d431b9b819c7bf428ba5a2ba326 Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Tue, 30 Jun 2026 07:56:31 -0700 Subject: [PATCH 28/44] feat(sc): add max_prompt_groups cap to StalenessSampler.select Signed-off-by: Yuki Huang --- .../async_utils/staleness_sampler.py | 12 +- nemo_rl/algorithms/single_controller.py | 13 +- .../test_staleness_sampler.py | 135 +++++++++++++++--- 3 files changed, 137 insertions(+), 23 deletions(-) diff --git a/nemo_rl/algorithms/async_utils/staleness_sampler.py b/nemo_rl/algorithms/async_utils/staleness_sampler.py index eae88d6b946..144dabdd3d2 100644 --- a/nemo_rl/algorithms/async_utils/staleness_sampler.py +++ b/nemo_rl/algorithms/async_utils/staleness_sampler.py @@ -57,8 +57,9 @@ async def select( *, current_train_weight: int, min_prompt_groups: int, + max_prompt_groups: int, ) -> tuple[KVBatchMeta | None, int]: - """Concat the first min_prompt_groups eligible groups and drop them from the buffer. + """Concat up to max_prompt_groups eligible groups and drop them from the buffer. Eligibility = ready and weight in [current_train_weight - max_staleness_versions, current_train_weight]. @@ -67,6 +68,7 @@ async def select( Args: current_train_weight: Current trainer weight version. min_prompt_groups: Minimum groups required; returns (None, 0) below this. + max_prompt_groups: Cap on groups returned when the threshold is met. Returns: meta: Concatenated KVBatchMeta, or None if not enough groups. @@ -74,6 +76,11 @@ async def select( """ if min_prompt_groups < 1: raise ValueError(f"min_prompt_groups must be >= 1, got {min_prompt_groups}") + if max_prompt_groups < min_prompt_groups: + raise ValueError( + f"max_prompt_groups ({max_prompt_groups}) must be >= " + f"min_prompt_groups ({min_prompt_groups})" + ) if self.force_in_order: # target_step exact match; staleness window ignored. @@ -119,7 +126,8 @@ async def select( ) ) - selected_idxs = valid_idxs[:min_prompt_groups] + requested_groups = min(len(valid_idxs), max_prompt_groups) + selected_idxs = valid_idxs[:requested_groups] selected_metas = [self._buffer.meta_list[i] for i in selected_idxs] await self._buffer.remove(selected_idxs, remove_in_dp=False) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 52f06209579..c9057fc2956 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -397,12 +397,19 @@ async def _train_pump(self) -> None: for _ in range(evicted): self._buffer_capacity.release() - # TODO @yukih: wait train pump merged, now always return min_prompt_groups_per_batch - # need to add a max_prompt_groups_per_batch + # Get train data with self._timer.time("exposed_generation"): + max_prompt_groups = ( + grpo_cfg["num_prompts_per_step"] - groups_dispatched + ) + min_prompt_groups = min( + self._async_cfg.min_prompt_groups_per_batch, + max_prompt_groups, + ) train_meta, num_groups = await self._sampler.select( current_train_weight=self._trainer_version, - min_prompt_groups=self._async_cfg.min_prompt_groups_per_batch, + min_prompt_groups=min_prompt_groups, + max_prompt_groups=max_prompt_groups, ) if train_meta is None: diff --git a/tests/unit/single_controller/test_staleness_sampler.py b/tests/unit/single_controller/test_staleness_sampler.py index d07c07fce4b..ce15f34acf8 100644 --- a/tests/unit/single_controller/test_staleness_sampler.py +++ b/tests/unit/single_controller/test_staleness_sampler.py @@ -76,14 +76,22 @@ def test_select_returns_none_when_insufficient(self): buf.add("g0", weight=5) sampler = StalenessSampler(buf, max_staleness_versions=2) - result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + result = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) + ) assert result == (None, 0) def test_select_returns_none_on_empty_buffer(self): buf = FakeBuffer() sampler = StalenessSampler(buf, max_staleness_versions=2) - result = _run(sampler.select(current_train_weight=5, min_prompt_groups=1)) + result = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=1, max_prompt_groups=1 + ) + ) assert result == (None, 0) def test_select_filters_by_staleness_window(self): @@ -97,7 +105,9 @@ def test_select_filters_by_staleness_window(self): ) selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=2) + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None @@ -114,7 +124,9 @@ def test_select_freshest_first_orders_by_lag(self): ) selected, num_groups = _run( - sampler.select(current_train_weight=6, min_prompt_groups=2) + sampler.select( + current_train_weight=6, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None assert selected.sample_ids == ["v5_g0", "v4_g0"] @@ -129,7 +141,9 @@ def test_select_fifo_orders_by_insertion(self): ) selected, num_groups = _run( - sampler.select(current_train_weight=6, min_prompt_groups=2) + sampler.select( + current_train_weight=6, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None assert selected.sample_ids == ["v3_g0", "v4_g0"] @@ -142,7 +156,9 @@ def test_select_skips_future_weight(self): sampler = StalenessSampler(buf, max_staleness_versions=10) selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=1) + sampler.select( + current_train_weight=5, min_prompt_groups=1, max_prompt_groups=1 + ) ) assert selected is not None @@ -156,7 +172,9 @@ def test_select_concats_groups(self): sampler = StalenessSampler(buf, max_staleness_versions=0) selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=2) + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None @@ -176,12 +194,18 @@ def test_select_strict_on_policy_requires_exact_version(self): sampler = StalenessSampler(buf, max_staleness_versions=0) # 3 eligible (need weight=5), only have 2 - result = _run(sampler.select(current_train_weight=5, min_prompt_groups=3)) + result = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=3, max_prompt_groups=3 + ) + ) assert result == (None, 0) # Buffer still intact: select with min=3 returned None without dropping anything. selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=2) + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None assert selected.sample_ids == ["g1_g0", "g2_g0"] @@ -194,7 +218,9 @@ def test_select_drops_returned_entries_from_buffer(self): sampler = StalenessSampler(buf, max_staleness_versions=0) first_meta, first_num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=1) + sampler.select( + current_train_weight=5, min_prompt_groups=1, max_prompt_groups=1 + ) ) assert first_meta is not None assert first_meta.sample_ids == ["g0_g0"] @@ -204,7 +230,9 @@ def test_select_drops_returned_entries_from_buffer(self): assert buf.remove_calls[-1][1] is False second_meta, second_num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=1) + sampler.select( + current_train_weight=5, min_prompt_groups=1, max_prompt_groups=1 + ) ) assert second_meta is not None assert second_meta.sample_ids == ["g1_g0"] @@ -214,7 +242,60 @@ def test_select_rejects_zero_min_prompt_groups(self): buf = FakeBuffer() sampler = StalenessSampler(buf, max_staleness_versions=0) with pytest.raises(ValueError): - _run(sampler.select(current_train_weight=0, min_prompt_groups=0)) + _run( + sampler.select( + current_train_weight=0, min_prompt_groups=0, max_prompt_groups=0 + ) + ) + + def test_select_rejects_max_less_than_min(self): + buf = FakeBuffer() + for i in range(3): + buf.add(f"g{i}", weight=5) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + with pytest.raises(ValueError): + _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=1 + ) + ) + + def test_select_caps_at_max_prompt_groups(self): + buf = FakeBuffer() + for i in range(5): + buf.add(f"g{i}", weight=5) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + selected, num_groups = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=3 + ) + ) + + assert selected is not None + # FIFO order; capped at max=3 even though 5 are eligible. + assert selected.sample_ids == ["g0_g0", "g1_g0", "g2_g0"] + assert num_groups == 3 + # The remaining two stay in the buffer. + assert buf.start_weight_list == [5, 5] + + def test_select_takes_all_available_when_between_min_and_max(self): + buf = FakeBuffer() + for i in range(3): + buf.add(f"g{i}", weight=5) + sampler = StalenessSampler(buf, max_staleness_versions=0) + + selected, num_groups = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=8 + ) + ) + + assert selected is not None + assert selected.sample_ids == ["g0_g0", "g1_g0", "g2_g0"] + assert num_groups == 3 + assert buf.start_weight_list == [] class TestStalenessSamplerEvict: @@ -288,7 +369,9 @@ def test_default_mode_skips_unready_slots(self): sampler = StalenessSampler(buf, max_staleness_versions=0) selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=1) + sampler.select( + current_train_weight=5, min_prompt_groups=1, max_prompt_groups=1 + ) ) assert selected is not None @@ -301,7 +384,11 @@ def test_default_mode_waits_when_too_few_ready(self): buf.add("g1", weight=5, ready=True) sampler = StalenessSampler(buf, max_staleness_versions=0) - result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + result = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) + ) assert result == (None, 0) @@ -314,7 +401,9 @@ def test_consumes_oldest_batch_first(self): sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=2) + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None @@ -333,7 +422,11 @@ def test_waits_when_oldest_batch_partially_ready(self): buf.add("v5_b", weight=5, ready=True) sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) - result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + result = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) + ) assert result == (None, 0) # Buffer untouched: nothing removed. assert buf.start_weight_list == [4, 4, 5, 5] @@ -345,7 +438,11 @@ def test_returns_none_when_oldest_batch_not_filled(self): # Only 1 ready in oldest batch; need 2. sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) - result = _run(sampler.select(current_train_weight=5, min_prompt_groups=2)) + result = _run( + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) + ) assert result == (None, 0) def test_ignores_future_versions_when_picking_target(self): @@ -358,7 +455,9 @@ def test_ignores_future_versions_when_picking_target(self): sampler = StalenessSampler(buf, max_staleness_versions=1, require_order=True) selected, num_groups = _run( - sampler.select(current_train_weight=5, min_prompt_groups=2) + sampler.select( + current_train_weight=5, min_prompt_groups=2, max_prompt_groups=2 + ) ) assert selected is not None From 05d18d68762d322beccddfe2b12f5501320fc01b Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Tue, 7 Jul 2026 01:18:26 -0700 Subject: [PATCH 29/44] refactor(sc): clear DP samples per sub-select Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 38 ++++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index c9057fc2956..5fafba3ae0b 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -202,7 +202,6 @@ def __init__( self._trainer_version: int = 0 self._train_steps: int = 0 - self._step_consumed_sample_ids: list[str] = [] self._step_log_dict: dict[str, list] = { "rewards": [], "masked_advantages": [], @@ -382,6 +381,7 @@ async def _train_pump(self) -> None: while self._train_steps < grpo_cfg["max_num_steps"]: step_id = f"sc-step-{self._train_steps:06d}" groups_dispatched = 0 + min_sample_version = None step_open = False with self._timer.time("total_step_time"): @@ -453,13 +453,32 @@ async def _train_pump(self) -> None: train_meta, ) - groups_dispatched += num_groups - self._step_consumed_sample_ids.extend(train_meta.sample_ids) if train_meta.sequence_lengths: self._step_log_dict["sequence_lengths"].extend( int(s) for s in train_meta.sequence_lengths ) + # Refresh min_sample_version + curr_min_sample_version = min( + t["weight_version"] + for t in train_meta.tags # type: ignore + ) + if min_sample_version is not None: + min_sample_version = min( + min_sample_version, curr_min_sample_version + ) + else: + min_sample_version = curr_min_sample_version + + # Remove consumed sample_ids from the buffer + await self._call_dp( + "clear_samples", + sample_ids=list(train_meta.sample_ids), + partition_id=self._partition_id, + ) + + groups_dispatched += num_groups + if not step_open: print( "train_pump: rollout exhausted before any group ready", @@ -471,13 +490,6 @@ async def _train_pump(self) -> None: result = await asyncio.to_thread( self._trainer.finish_train_step, step_id ) - consumed_ids = list(self._step_consumed_sample_ids) - self._step_consumed_sample_ids = [] - await self._call_dp( - "clear_samples", - sample_ids=list(consumed_ids), - partition_id=self._partition_id, - ) step_metrics = aggregate_step_metrics(result) step_metrics.update( @@ -528,13 +540,11 @@ async def _train_pump(self) -> None: # min sample version refers to the version each consumed sample was # generated with; lag = current trainer version - oldest sample version. - min_sample_version = min(t["weight_version"] for t in train_meta.tags) # type: ignore - lag = self._trainer_version - min_sample_version + lag = self._trainer_version - min_sample_version # type: ignore print( f"train step {self._train_steps}/{grpo_cfg['max_num_steps']} " f"trainer_v={self._trainer_version} " - f"lag={lag} " - f"batch_size={len(consumed_ids)}", + f"lag={lag} ", flush=True, ) From fe8ac47b731816d79897fdd5b63b45c3d62a79dd Mon Sep 17 00:00:00 2001 From: Yuki Huang Date: Tue, 7 Jul 2026 01:45:07 -0700 Subject: [PATCH 30/44] fix exposed_generation Signed-off-by: Yuki Huang --- nemo_rl/algorithms/single_controller.py | 39 +++++++++++++++---------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 5fafba3ae0b..f258bcc7430 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -386,19 +386,23 @@ async def _train_pump(self) -> None: with self._timer.time("total_step_time"): while groups_dispatched < grpo_cfg["num_prompts_per_step"]: - await asyncio.sleep(0) + # Wait for a selectable batch + with self._timer.time("exposed_generation"): + await asyncio.sleep(0) - # evict stale groups - evicted = await self._sampler.evict( - current_train_weight=self._trainer_version, - ) - if evicted: - print(f" evicted {evicted} stale prompt group(s)", flush=True) - for _ in range(evicted): - self._buffer_capacity.release() + # Evict stale groups + evicted = await self._sampler.evict( + current_train_weight=self._trainer_version, + ) + if evicted: + print( + f" evicted {evicted} stale prompt group(s)", + flush=True, + ) + for _ in range(evicted): + self._buffer_capacity.release() - # Get train data - with self._timer.time("exposed_generation"): + # Select a batch max_prompt_groups = ( grpo_cfg["num_prompts_per_step"] - groups_dispatched ) @@ -412,12 +416,14 @@ async def _train_pump(self) -> None: max_prompt_groups=max_prompt_groups, ) - if train_meta is None: - await asyncio.sleep(0.05) - continue + # If no batch is selectable, sleep and retry + if train_meta is None: + await asyncio.sleep(0.05) + continue - for _ in range(num_groups): - self._buffer_capacity.release() + # Release buffer capacity + for _ in range(num_groups): + self._buffer_capacity.release() # Compute prev_logprobs / ref_logprobs with self._timer.time("logprob_inference_prep"): @@ -433,6 +439,7 @@ async def _train_pump(self) -> None: train_meta, ) + # Compute advantages with self._timer.time("advantage_calculation"): train_meta = await self._advantage_pump(train_meta) From b06727aaa12df0d4679d1a19fc77d4261ebc42fc Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Mon, 27 Jul 2026 22:58:07 -0700 Subject: [PATCH 31/44] =?UTF-8?q?feat(sc):=20S1=20token-capture=20primitiv?= =?UTF-8?q?es=20=E2=80=94=20TQ=20sink/source,=20TokenCaptureConfig,=20repl?= =?UTF-8?q?ay-buffer=20surgery?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RL half of stage S1 of docs/design-docs/tq-gym-gate-authoritative.md (dormant by default: token_capture.enabled=false leaves every legacy codepath unchanged; un-gated changes below are disclosed in the implementation log for gate sign-off): - nemo_rl/data_plane/tq_token_sink.py: TQTokenSink/TQTokenSource implementing Gym's staging protocols over put_samples/get_samples (float32-exact digests; conformance kit green vs a live TQ backend). - TokenCaptureConfig (BaseModel, enabled=False) on MasterConfig. - TQReplayBuffer: commit_finalized (slot effective version = group_min_wv), abort, rollout_ids on slots, staging-aware remove; evicted-slot commit fix (un-gated bug fix). - SingleController: _buffer_capacity release on dispatch exception, paired with generate_and_push aborting its reserved slot (un-gated bug fix). - setup.py: flag-gated pre-registration of rollout_data + rollout_staging (TQ lazy-field controller race). - Gym submodule pin -> tq-gate-capture branch (base = upstream #2124 head 32b555f04): S1 primitives (records/protocols/digest/lineage/rebuild/ conformance) grouped under nemo_gym/token_id_capture/staging/; uv.lock regenerated for the new pin (un-gated). - Tests: test_tq_replay_buffer 18/18, test_tq_token_sink 7/7 (--nemo-gym-only), test_rollout_manager 8/8 (incl. pre-broken _FakeBuffer fix); Gym-side 46/46 incl. #2124's base suite. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- 3rdparty/Gym-workspace/Gym | 2 +- ...m-gate-authoritative-implementation-log.md | 163 ++ .../algorithms/async_utils/replay_buffer.py | 135 +- nemo_rl/algorithms/single_controller.py | 6 + .../single_controller_utils/config.py | 30 + .../single_controller_utils/setup.py | 30 + nemo_rl/data_plane/tq_token_sink.py | 188 +++ nemo_rl/experience/rollout_manager.py | 26 +- tests/unit/data_plane/test_tq_token_sink.py | 111 ++ tests/unit/experience/test_rollout_manager.py | 49 +- .../test_tq_replay_buffer.py | 206 +++ uv.lock | 1338 ++++++++++++++++- 12 files changed, 2209 insertions(+), 75 deletions(-) create mode 100644 docs/design-docs/tq-gym-gate-authoritative-implementation-log.md create mode 100644 nemo_rl/data_plane/tq_token_sink.py create mode 100644 tests/unit/data_plane/test_tq_token_sink.py diff --git a/3rdparty/Gym-workspace/Gym b/3rdparty/Gym-workspace/Gym index 610a08ab5fe..61fbb660a83 160000 --- a/3rdparty/Gym-workspace/Gym +++ b/3rdparty/Gym-workspace/Gym @@ -1 +1 @@ -Subproject commit 610a08ab5fe9f8f5fb5fff36b170429ea67f0f92 +Subproject commit 61fbb660a83d0f30f3c45933d52426fc36216d08 diff --git a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md new file mode 100644 index 00000000000..0042bd17ae9 --- /dev/null +++ b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md @@ -0,0 +1,163 @@ +# Implementation Log — Token Capture v3 (Gate Token Custody) + +Tracks stage-by-stage progress of `tq-gym-gate-authoritative.md` (MVP: S1–S5, +one PR, sign-off gates between stages). Branch: `yukih/sc-entrypoint`. + +Standing constraints (user-mandated): + +- **Dormant by default.** `token_capture.enabled=false` is the default; every + legacy codepath must behave exactly as before. Any change that affects + behavior regardless of the flag (bug fixes, submodule pin bumps) is + disclosed explicitly at the stage gate for sign-off. +- Wire shapes (§ 3.4) and the serving rule (§ 3.3) freeze at the S1 gate. + +Environment: dev node with 8×H100 for stage-gate test runs. +Prototype donor checkout: `/lustre/fsw/portfolios/coreai/users/pthombre/gym/RL` +(branch `pranav/tq_gym_prototype` @ `05e0adfa0`, Gym pin `6ea5810`). + +--- + +## S1 — primitives (Gym fork) + buffer surgery (RL repo) + +Status: **SIGNED OFF (user review, 2026-07-28).** Wire shapes and the serving +rule are frozen. Post-review closeout below (subpackage restructure done; +regression evidence recorded as it lands). + +### Gym fork (submodule branch `tq-gate-capture`) + +Base: **upstream PR #2124 head `32b555f04`** (= upstream main @ `fa0c2da3` ++ the token-id-capture core), per § 9.2. S1 work is two commits on top: +`70e43b60` "feat(token-id-capture): S1 gate-authoritative capture primitives" +and `61fbb660` "refactor(token-id-capture): move S1 capture core into +staging/ subpackage" (the post-review restructure; see Open TODOs). + +| Item | Status | Notes | +|---|---|---| +| records.py wire shapes | done | StagedCallRecord / StageResult / CommitCoords / CallRecord / RolloutReceipt / StagedCallSnapshot, `staging_key()`, `SCHEMA_VERSION=1`; reserved `chain_hash`/`cum_hash` fields for H2 | +| protocols.py | done | TokenSink / TokenSource / WeightVersionProvider / CaptureAdapter protocols; `install_capture` signature frozen (body lands in S2 `capture.py`) | +| digest.py | done | `compute_staging_digest`, encoders, `build_staging_delta` — **verified byte-identical to the prototype donor** (`rollout_writer.py`) on golden vectors incl. -0.0/NaN-adjacent cases | +| lineage.py | done | pure `RolloutLineage` (admit/commit/fail/seal → manifest) + create-only `LineageRegistry` with TTL sweep; no leases/hash-claims — the marker names the parent explicitly | +| rebuild.py | done | `snapshots_to_entries` (mask-driven, **verified equal to the prototype's `StagedSnapshotTokenSource.entries()`** on the worked-example forest incl. the c3 fork) + `linearize(main_chain_only, terminal_hint)` | +| conformance kit | done | 4 golden fixtures (worked example § 4.1, single-call, capture-failed, mixed-wv); `run_lineage_conformance` + `run_sink_source_conformance`; goldens frozen | +| purity rule | done | core modules import with no fastapi/ray/torch/TQ/aiohttp (subprocess-import test); `token_id_capture/__init__` resolves the #2124 reader/route exports lazily (PEP 562) so the core stays pure with the public API unchanged | +| tests | done | `tests/unit_tests/test_token_capture_gate_primitives.py` — 24 tests; **44/44 green including #2124's 20-test base suite** (the S3 base sanity check, already green at S1) | + +### NeMo-RL repo + +| Item | Status | Notes | +|---|---|---| +| `nemo_rl/data_plane/tq_token_sink.py` | done | TQTokenSink / TQTokenSource over put_samples/get_samples; 3 jagged + 2 scalar columns per staged row; parent pointers rejoined from the manifest by the finalizer | +| `TokenCaptureConfig` (`single_controller_utils/config.py`) | done | pydantic BaseModel on MasterConfig, `enabled=False` default; staging_partition / on_capture_failure / mixed_weight_version_policy / min_valid_fraction_per_group / TTLs | +| TQReplayBuffer surgery (`async_utils/replay_buffer.py`) | done | `commit_finalized` (slot's effective version = `group_min_wv`), `abort`, `rollout_ids` on slots, staging-aware `remove`; evicted-slot `commit` fix (pre-write check + un-write on mid-write eviction) | +| `_buffer_capacity` leak fix (`single_controller.py:319`) | done | release on dispatch exception, paired with `generate_and_push` aborting the reserved slot so eviction never double-releases | +| Partition pre-registration (`setup.py`) | done | registers `rollout_data` + `rollout_staging` from the driver thread, **gated on `token_capture.enabled`** (the TQ lazy-field controller race) | +| Tests | done | `test_tq_replay_buffer.py` 18/18 (new: token-capture mode + evicted-commit classes); `test_tq_token_sink.py` 7/7 — **conformance kit green against a live TQ simple backend** (byte-exact digests through float32 storage); `test_rollout_manager.py` 8/8 (2 new failure-path tests) | + +### S1-gate checklist (§ 10) + +- **Submodule fork logistics**: local branch `tq-gate-capture` on the vendored + submodule; base = `refs/pull/2124/head` @ `32b555f04` fetched from + `NVIDIA-NeMo/Gym` origin. **Open decision for sign-off**: where the gitlink + should point for CI (fork remote vs. an NVIDIA-NeMo/Gym branch) — the rev + currently exists only locally. +- **Leaf package importable in the worker venv**: `nemo_gym.token_id_capture` + core modules import in the RL venv with zero serving deps (purity test); + worker `py_executable` check to be repeated in S2 when `install_capture` + is wired into the vLLM worker. +- **vLLM prefix-ids + splice validated** (scratchpad + `validate_prefix_ids_vllm.py`, 1×H100): + - Template-level splice (`_replace_prefix_tokens`) for the functional-test + templates **Qwen/Qwen3-0.6B** (SC DP functional test) and + **Qwen/Qwen2.5-1.5B-Instruct** (SC exemplar): exact model prefix + preserved under retokenization drift (Qwen3's history-render strips + `` blocks — retokenization_differs=True — and the splice handles it). + - Live vLLM token-in smoke (Qwen3-0.6B): turn-2 `TokensPrompt` of spliced + exact ids → `out.prompt_token_ids == spliced` (exact prefix conditioning, + 47-token prefix), native generated-id + logprob extraction with no string + parsing and no `/tokenize` round trip. + +### Open TODOs (pre-sign-off) + +- [x] **Group the S1 modules into a subpackage** — done post-sign-off + (2026-07-28), Gym fork commit `61fbb660` (a follow-up commit, not an amend). + `records.py` (staging shapes, split back out; #2124's `records.py` reverts + to base-identical) + `protocols.py` / `digest.py` / `lineage.py` / + `rebuild.py` / `conformance/` now live under + `nemo_gym/token_id_capture/staging/`; `staging/__init__` re-exports the + wire shapes + protocols (the disclosure-5 name collision dissolves into + namespacing); the purity test now globs the subpackage instead of a + hand-maintained list (46/46 green, incl. #2124's 20-test base suite). + RL-side imports (`tq_token_sink.py`, `test_tq_token_sink.py` — 7/7 green + vs live TQ after the move) and the design doc's § 3.0/§ 9.3 paths updated. + S2's `capture.py` lands in `staging/`; `adapters/` and gate hosting stay + outside the purity scope. + +### Deviations / disclosures (for S1 sign-off) + +1. **Gym submodule pin moves `610a08ab` → `61fbb660`** (= #2124 head + S1 + commits; ~50 upstream commits ahead of the old pin). Attempted alternative — + cherry-picking #2124 onto the old pin — required hand-merging its + prerequisite (#1715 observability capture, 34 files / 2.7k lines) into an + upstream-untested combination; rejected in favor of the design's + prescribed base. **This changes Gym behavior with the flag off**; the + flag-off SC gym functional test is the regression evidence to run at the + gate (queued; see below). +2. **`uv.lock` regenerated** for the new pin (aiohttp 3.13.3→3.14.1 floor, + +simple-websocket/toml/websocket-client, starlette/typing-extensions + bumps). Affects all environments regardless of the flag. +3. **Bug fixes active with the flag off** (all disclosed by design §§ 9.1): + evicted-slot `commit` no longer orphans TQ rows; `_buffer_capacity` no + longer leaks on failed dispatch (failed dispatch now also aborts its + reserved slot instead of leaving a phantom entry until staleness eviction). +4. **`#2124` API preserved via lazy exports**: `token_id_capture/__init__` + now resolves reader/route/source names through module `__getattr__` + (required by the § 3.0 purity rule). No call-site changes. +5. **Protocol naming**: the design's `TokenSink`/`TokenSource` protocols + collide with names #2124 already exports; they live in + `token_id_capture/protocols.py` and are imported by module path, not + re-exported from the package root. +6. **Purity enforcement** is a subprocess-import unit test rather than an + import-linter dependency (same guarantee, no new Gym dependency). +7. **Pre-existing test breakage fixed**: `test_rollout_manager.py`'s + `_FakeBuffer` lacked the `target_step` kwarg (broken before this work); + fixed while adding the new failure-path tests. + +### Regression evidence (flag off) + +- `tests/unit/test_config_validation.py` + `test_config_v2.py`: **476 passed**. +- `tests/unit/experience/`: 8/8; `tests/unit/single_controller/test_tq_replay_buffer.py`: 18/18. +- Full `tests/unit/single_controller/` + `tests/unit/experience/` suite + (2026-07-28, `NRL_FORCE_REBUILD_VENVS=true` venv rebuild first): **59 + passed; 10 failures, all pre-existing at branch HEAD** (each reproduced + byte-identically with ALL working-tree changes stashed — committed test + fixtures out of sync with committed branch code, not this work): + - `test_rollout_pump.py::test_rollout_pump_writes_expected_tq_data` — + SC actor init reads `master_config.logger` (`single_controller.py:116`, + committed 2026-06-21) but the test's `MasterConfig.model_construct` + never sets the required `logger` field → actor creation dies → + 0 rows in TQ. (The prior session's "Ray-version mismatch" diagnosis was + the venv symptom; after rebuild this is the real, deterministic cause.) + - 9 × `test_single_controller_setup.py::TestSetup::*` — `KeyError: + 'seed'`: `setup_single_controller` calls `set_seed(grpo_config["seed"])` + (commit `888cb8eeb`) but the test's `_make_master_config` has no + `grpo.seed`. + Flagged for the user at the gate (fixable as a test-fixture patch, but + left untouched to keep the stage diff clean). +- SC functional tests (`L1_Functional_Tests_SingleController.sh`, 8×H100) + with the flag off: planned as pin-bump regression evidence at the gate. + +## S2 — capture core + vLLM adapter + worker hosting + +Status: not started (blocked on S1 sign-off) + +## S3 — Gym gate + +Status: not started (blocked on S2 sign-off) + +## S4 — receipts, finalizer, SC integration + +Status: not started (blocked on S3 sign-off) + +## S5 — verification + +Status: not started (blocked on S4 sign-off) diff --git a/nemo_rl/algorithms/async_utils/replay_buffer.py b/nemo_rl/algorithms/async_utils/replay_buffer.py index cab8685de75..10975aac286 100644 --- a/nemo_rl/algorithms/async_utils/replay_buffer.py +++ b/nemo_rl/algorithms/async_utils/replay_buffer.py @@ -570,10 +570,15 @@ def __init__( partition_id: str, *, pad_value_dict: Mapping[str, int], + staging_partition_id: Optional[str] = None, ): self._dp_client = dp_client self._partition_id = partition_id self._pad_value_dict = dict(pad_value_dict) + # Token-capture mode only (docs/design-docs/tq-gym-gate-authoritative.md): + # the staging partition whose per-call delta rows `remove` must clear + # alongside the canonical rows. None on the legacy path. + self._staging_partition_id = staging_partition_id self.meta_list: list[Optional[KVBatchMeta]] = [] self.start_weight_list: list[int] = [] self.end_weight_list: list[int] = [] @@ -581,6 +586,9 @@ def __init__( self.target_step_list: list[Optional[int]] = [] self.ready_list: list[bool] = [] self._group_ids: list[str] = [] + # Parallel to the lists above; populated only in token-capture mode. + self._rollout_ids_list: list[Optional[list[str]]] = [] + self._staging_keys_list: list[Optional[list[str]]] = [] def reserve( self, @@ -588,6 +596,7 @@ def reserve( weight_version: int, target_step: Optional[int] = None, group_id: Optional[str] = None, + rollout_ids: Optional[list[str]] = None, ) -> str: """Append an unready slot tagged with weight_version. @@ -595,6 +604,9 @@ def reserve( weight_version: Weight version stamped on the slot. target_step: Training step this slot targets; only consulted by StalenessSampler.force_in_order. group_id: Per-group sample_id prefix; defaults to a fresh uuid4. + rollout_ids: Token-capture mode: the gate-registered rollout ids + this slot dispatched, recorded so cleanup can name what it + owns even before a receipt exists. Returns: group_id used by the matching commit. @@ -607,6 +619,10 @@ def reserve( self.target_step_list.append(target_step) self.ready_list.append(False) self._group_ids.append(group_id) + self._rollout_ids_list.append( + list(rollout_ids) if rollout_ids is not None else None + ) + self._staging_keys_list.append(None) return group_id async def commit( @@ -631,6 +647,14 @@ async def commit( Raises: ValueError: group_id has no live slot (removed or never reserved). """ + # Check the slot is still live BEFORE writing: a slot evicted while + # its rollout was in flight used to fail here only after put_samples, + # leaking N orphaned rows into the partition. + if group_id not in self._group_ids: + raise ValueError( + f"TQReplayBuffer.commit: group {group_id} has no live slot " + "(evicted or never reserved); nothing written" + ) train_batch = record_to_train_batch(record, pad_value_dict=self._pad_value_dict) sample_ids, fields, tags = pack_payload( train_batch, weight_version=start_weight_version, group_id=group_id @@ -654,15 +678,107 @@ async def commit( tags=[dict(t) for t in tags], ) - idx = self._group_ids.index(group_id) + try: + idx = self._group_ids.index(group_id) + except ValueError: + # Evicted during the awaited write: un-write the rows so the + # partition holds nothing the buffer no longer tracks. + await self._call_dp( + "clear_samples", + sample_ids=list(sample_ids), + partition_id=self._partition_id, + ) + raise ValueError( + f"TQReplayBuffer.commit: group {group_id} was evicted during " + "the write; rows cleared" + ) from None self.meta_list[idx] = meta self.end_weight_list[idx] = end_weight_version self.ready_list[idx] = True return meta + async def commit_finalized( + self, + group_id: str, + meta: KVBatchMeta, + group_min_wv: int, + group_max_wv: int, + *, + staging_keys: Optional[list[str]] = None, + ) -> KVBatchMeta: + """Mark a slot ready from finalizer output (token-capture mode). + + Unlike :meth:`commit`, the canonical rows are already in TQ — the + finalizer tensorized and put them — so this only fills the slot. + The slot's effective version is the group's OLDEST call version + (``group_min_wv``): staleness accounting stays conservative when a + rollout straddles a refit. + + Args: + group_id: group_id returned by the matching reserve call. + meta: KVBatchMeta the finalizer built over its published rows. + group_min_wv: Oldest weight version any call in the group used. + group_max_wv: Newest weight version any call in the group used. + staging_keys: The group's staged delta keys, recorded so + :meth:`remove` can clear the staging partition too. + + Raises: + ValueError: group_id has no live slot (removed or never reserved). + """ + try: + idx = self._group_ids.index(group_id) + except ValueError: + raise ValueError( + f"TQReplayBuffer.commit_finalized: group {group_id} has no " + "live slot (evicted or never reserved)" + ) from None + self.meta_list[idx] = meta + self.start_weight_list[idx] = group_min_wv + self.end_weight_list[idx] = group_max_wv + self.ready_list[idx] = True + self._staging_keys_list[idx] = ( + list(staging_keys) if staging_keys is not None else None + ) + return meta + + def abort(self, group_id: str) -> bool: + """Drop an unready slot whose dispatch failed or was cancelled. + + Token-capture mode; called from the failed dispatch path. + No DataPlane rows are cleared: an unready slot published no canonical + rows, and its staged deltas (keys unknown before a receipt) are swept + by the staging TTL backstop. + + Returns: + True when a slot was dropped; False when the group_id has no + live slot (already committed+consumed or never reserved). + """ + try: + idx = self._group_ids.index(group_id) + except ValueError: + return False + if self.ready_list[idx]: + return False + self._delete_slot(idx) + return True + + def _delete_slot(self, idx: int) -> None: + del self.meta_list[idx] + del self.start_weight_list[idx] + del self.end_weight_list[idx] + del self.target_step_list[idx] + del self.ready_list[idx] + del self._group_ids[idx] + del self._rollout_ids_list[idx] + del self._staging_keys_list[idx] + async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: """Drop entries at the given indices and optionally clear them from DataPlane. + In token-capture mode (``staging_partition_id`` set), clearing a + group also clears its recorded staged delta rows, so eviction leaves + neither canonical nor staging bytes behind. + Args: idxs: Entry indices to drop. Must be within [0, size). remove_in_dp: If True, also clear the dropped rows from DataPlane. @@ -681,16 +797,15 @@ async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: ) dropped_sample_ids: list[str] = [] + dropped_staging_keys: list[str] = [] for i in drop_idxs: meta = self.meta_list[i] if meta is not None: dropped_sample_ids.extend(meta.sample_ids) - del self.meta_list[i] - del self.start_weight_list[i] - del self.end_weight_list[i] - del self.target_step_list[i] - del self.ready_list[i] - del self._group_ids[i] + staging_keys = self._staging_keys_list[i] + if staging_keys: + dropped_staging_keys.extend(staging_keys) + self._delete_slot(i) if remove_in_dp: await self._call_dp( @@ -698,6 +813,12 @@ async def remove(self, idxs: list[int], remove_in_dp: bool) -> int: sample_ids=dropped_sample_ids, partition_id=self._partition_id, ) + if dropped_staging_keys and self._staging_partition_id is not None: + await self._call_dp( + "clear_samples", + sample_ids=dropped_staging_keys, + partition_id=self._staging_partition_id, + ) return len(drop_idxs) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index f258bcc7430..e9020f87aec 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -316,6 +316,12 @@ async def _dispatch_one_prompt( content = prompt["message_log"][i]["content"] break print(f" rollout done for prompt='{content[:20]}...'", flush=True) + except BaseException: + # A failed dispatch never reaches the train pump, so its + # _buffer_capacity slot (released there per consumed group) + # would leak and eventually starve the rollout pump. + self._buffer_capacity.release() + raise finally: self._inflight_rollouts -= 1 sem.release() diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py index 9ffa122adc5..4eb85bd4c85 100644 --- a/nemo_rl/algorithms/single_controller_utils/config.py +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -50,6 +50,35 @@ class AsyncRLConfig(BaseModel, extra="allow"): force_in_order: bool = False +class TokenCaptureConfig(BaseModel, extra="allow"): + """Gate-authoritative token capture (token-in/token-out via NeMo-Gym). + + Dormant by default: with ``enabled=False`` every legacy codepath behaves + exactly as before — no staging partition is registered, no gate is + installed, and rollouts ride the token-echo path. See + docs/design-docs/tq-gym-gate-authoritative.md. + """ + + enabled: bool = False + # TQ partition holding per-call staged token deltas (cleared by the + # finalizer; distinct from the canonical rollout partition). + staging_partition: str = "rollout_staging" + # A failed worker-side stage poisons the rollout; "continue" serves the + # completion and lets the finalizer emit a placeholder row, "abort" fails + # the whole rollout at the gate. + on_capture_failure: Literal["continue", "abort"] = "continue" + # "allow" trains groups whose calls span a refit (staleness accounted via + # group_min_wv); "reject" placeholders them. Strict modes beyond the MVP + # matrix raise NotImplementedError at setup. + mixed_weight_version_policy: Literal["allow", "reject"] = "allow" + # Drop the whole group when fewer than this fraction of its rollouts + # produced valid rows (None keeps every group). + min_valid_fraction_per_group: Optional[float] = None + # Gate-side cleanup backstops. + registration_ttl_s: float = 3600.0 + staging_ttl_s: float = 3600.0 + + class MasterConfig(BaseModel, extra="allow"): policy: PolicyConfig loss_fn: ClippedPGLossConfig @@ -61,6 +90,7 @@ class MasterConfig(BaseModel, extra="allow"): checkpointing: CheckpointingConfig data_plane: DataPlaneConfig async_rl: AsyncRLConfig = Field(default_factory=AsyncRLConfig) + token_capture: TokenCaptureConfig = Field(default_factory=TokenCaptureConfig) # ── Internal SingleController configs ──────────────────────────────────── diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index abae6882c64..12fac785c6e 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -350,6 +350,33 @@ def setup_single_controller( # Connect-only DP client; TQPolicy already bootstrapped the controller. dp_client = build_data_plane_client(dp_cfg, bootstrap=False) + # Token-capture mode: pre-register both rollout partitions from this + # single driver thread before any producer is live. TQ's controller + # registers unseen field names lazily inside update_production_status + # without a lock, so the first concurrent puts into an unregistered + # partition can race kv_retrieve_meta and kill the controller thread + # (see TQDataPlaneClient.register_partition). + token_capture_cfg = master_config.token_capture + if token_capture_cfg.enabled: + from nemo_rl.data_plane.schema import DP_TRAIN_FIELDS + from nemo_rl.data_plane.tq_token_sink import STAGING_FIELDS + + group_size = grpo_config["num_generations_per_prompt"] + num_rollout_samples = master_config.async_rl.max_buffered_rollouts * group_size + dp_client.register_partition( + partition_id=partition_id, + fields=list(DP_TRAIN_FIELDS), + num_samples=num_rollout_samples, + consumer_tasks=["prev_lp", "ref_lp", "train"], + grpo_group_size=group_size, + ) + dp_client.register_partition( + partition_id=token_capture_cfg.staging_partition, + fields=list(STAGING_FIELDS), + num_samples=num_rollout_samples, + consumer_tasks=["finalize"], + ) + backend = generation_config["backend"] weight_synchronizer = create_weight_synchronizer( policy=policy, @@ -372,6 +399,9 @@ def setup_single_controller( dp_client, partition_id=partition_id, pad_value_dict={"token_ids": pad_id, "input_ids": pad_id}, + staging_partition_id=( + token_capture_cfg.staging_partition if token_capture_cfg.enabled else None + ), ) rollout_manager = RolloutManager( tokenizer=tokenizer, diff --git a/nemo_rl/data_plane/tq_token_sink.py b/nemo_rl/data_plane/tq_token_sink.py new file mode 100644 index 00000000000..c827750964a --- /dev/null +++ b/nemo_rl/data_plane/tq_token_sink.py @@ -0,0 +1,188 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""TransferQueue implementations of NeMo-Gym's token staging protocols. + +``TQTokenSink``/``TQTokenSource`` are NeMo-RL's providers for the +gate-authoritative capture design (docs/design-docs/tq-gym-gate-authoritative.md): +the sink is the worker-side write of one model call's token delta to the +``rollout_staging`` partition — the design's only heavy token hop — and the +source is the finalizer's read-back of those rows by staging key. This module +is the only hot-path file that knows tokens live in TQ; Gym sees opaque +staging keys. + +Each staged row carries three jagged columns (``token_ids_delta``, +``token_mask_delta``, ``generation_logprobs_delta``) plus scalar ``prev_len`` +and ``weight_version`` columns so a fetched row round-trips to a complete +``StagedCallSnapshot`` (parent pointers are lineage state and are rejoined +from the receipt manifest by the finalizer). Masks/logprobs are float32 on +the wire, matching ``compute_staging_digest``'s float32-bit-pattern scheme, +so the finalizer's digest recomputation over fetched values is byte-exact. +""" + +from __future__ import annotations + +from typing import Any, Optional + +import ray +import torch +from tensordict import TensorDict + +from nemo_gym.token_id_capture.staging.records import ( + StagedCallRecord, + StagedCallSnapshot, + StageResult, +) + +STAGING_FIELDS = [ + "token_ids_delta", + "token_mask_delta", + "generation_logprobs_delta", + "prev_len", + "weight_version", +] + + +def _call_dp(dp_client: Any, method_name: str, **kwargs: Any) -> Any: + """Call a DataPlaneClient method on a local client or a Ray actor handle.""" + method = getattr(dp_client, method_name) + remote = getattr(method, "remote", None) + if remote is not None: + return ray.get(remote(**kwargs)) + return method(**kwargs) + + +class TQTokenSink: + """Gym ``TokenSink`` over ``DataPlaneClient.put_samples``. + + ``stage`` is synchronous and returns only after TQ acknowledged the + write, so the capture layer's fail-closed ordering (bytes durable before + the model call is acked) holds by construction. Failures are reported in + the ``StageResult`` — the caller decides whether the rollout poisons or + aborts (``token_capture.on_capture_failure``). + """ + + def __init__(self, dp_client: Any, *, staging_partition: str) -> None: + self._dp_client = dp_client + self._staging_partition = staging_partition + + def stage(self, record: StagedCallRecord) -> StageResult: + key = record.staging_key + try: + fields = TensorDict( + { + "token_ids_delta": torch.tensor( + [record.token_ids_delta], dtype=torch.int64 + ), + "token_mask_delta": torch.tensor( + [record.token_mask_delta], dtype=torch.float32 + ), + "generation_logprobs_delta": torch.tensor( + [record.generation_logprobs_delta], dtype=torch.float32 + ), + "prev_len": torch.tensor([record.prev_len], dtype=torch.int64), + "weight_version": torch.tensor( + [record.weight_version], dtype=torch.int64 + ), + }, + batch_size=[1], + ) + tags = [ + { + "rollout_id": record.rollout_id, + "call_id": record.call_id, + "parent_call_id": record.parent_call_id, + "prev_len": record.prev_len, + "new_len": record.new_len, + "weight_version": record.weight_version, + "digest": record.digest, + "schema_version": record.schema_version, + } + ] + _call_dp( + self._dp_client, + "put_samples", + sample_ids=[key], + partition_id=self._staging_partition, + fields=fields, + tags=tags, + ) + except Exception as error: # noqa: BLE001 — any failure must poison, not crash serving + return StageResult( + ok=False, staging_key=key, error=f"{type(error).__name__}: {error}" + ) + return StageResult(ok=True, staging_key=key) + + def clear(self, staging_keys: list[str]) -> None: + """Drop staged rows (finalizer / eviction cleanup).""" + if not staging_keys: + return + _call_dp( + self._dp_client, + "clear_samples", + sample_ids=list(staging_keys), + partition_id=self._staging_partition, + ) + + +class TQTokenSource: + """Gym ``TokenSource`` over ``DataPlaneClient.get_samples``. + + Rows are fetched one key at a time (deltas are jagged across calls) in + the order requested. A missing or unreadable row raises ``KeyError`` per + the protocol — the finalizer maps that to a placeholder, never a silent + skip. + """ + + def __init__(self, dp_client: Any, *, staging_partition: str) -> None: + self._dp_client = dp_client + self._staging_partition = staging_partition + + def fetch(self, staging_keys: list[str]) -> list[StagedCallSnapshot]: + snapshots: list[StagedCallSnapshot] = [] + for key in staging_keys: + _, _, call_id = key.rpartition("/") + try: + row = _call_dp( + self._dp_client, + "get_samples", + sample_ids=[key], + partition_id=self._staging_partition, + select_fields=STAGING_FIELDS, + ) + snapshots.append(_row_to_snapshot(call_id, row)) + except KeyError: + raise + except Exception as error: # noqa: BLE001 — protocol maps any miss to KeyError + raise KeyError( + f"staged row {key!r} could not be fetched: {error}" + ) from error + return snapshots + + +def _row_to_snapshot(call_id: str, row: Any) -> StagedCallSnapshot: + def _leaf(name: str) -> torch.Tensor: + value = row[name] + tensor = value[0] if value.dim() > 1 or value.numel() > 1 else value + return tensor.reshape(-1) + + prev_len = int(_leaf("prev_len")[0].item()) + weight_version: Optional[int] = int(_leaf("weight_version")[0].item()) + return StagedCallSnapshot( + call_id=call_id, + prev_len=prev_len, + token_ids_delta=[int(t) for t in _leaf("token_ids_delta").tolist()], + token_mask_delta=[float(m) for m in _leaf("token_mask_delta").tolist()], + logprobs_delta=[float(p) for p in _leaf("generation_logprobs_delta").tolist()], + weight_version=weight_version, + ) diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index f382ab7af18..398b028f623 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -658,12 +658,20 @@ async def generate_and_push( weight_version=start_version, target_step=target_step ) - record = await self.run_rollout(input_sample) - end_version = self._weight_version - - await self._tq_buffer.commit( - group_id, - record, - start_weight_version=start_version, - end_weight_version=end_version, - ) + try: + record = await self.run_rollout(input_sample) + end_version = self._weight_version + + await self._tq_buffer.commit( + group_id, + record, + start_weight_version=start_version, + end_weight_version=end_version, + ) + except BaseException: + # A slot that will never commit must not linger as a phantom + # unready entry until staleness eviction — drop it now so buffer + # occupancy and _buffer_capacity stay in step (the dispatch task + # releases the capacity permit on the same exception). + self._tq_buffer.abort(group_id) + raise diff --git a/tests/unit/data_plane/test_tq_token_sink.py b/tests/unit/data_plane/test_tq_token_sink.py new file mode 100644 index 00000000000..d91bc1abb02 --- /dev/null +++ b/tests/unit/data_plane/test_tq_token_sink.py @@ -0,0 +1,111 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""TQTokenSink / TQTokenSource against a live TQ backend. + +Runs NeMo-Gym's installable conformance kit (golden call sequences → +byte-exact digests, manifests, and linearized rows) over the TransferQueue +implementations — the framework-CI half of the § 3.0 contract — plus the +protocol edges the kit does not cover (missing keys, stage failure shape). +""" + +from __future__ import annotations + +import pytest + +nemo_gym = pytest.importorskip("nemo_gym.token_id_capture.staging") + +from nemo_gym.token_id_capture.staging.conformance import ( # noqa: E402 + build_fixture_artifacts, + fixture_names, + load_fixture, + run_sink_source_conformance, +) +from nemo_gym.token_id_capture.staging.protocols import ( # noqa: E402 + TokenSink as TokenSinkProtocol, +) +from nemo_gym.token_id_capture.staging.protocols import ( # noqa: E402 + TokenSource as TokenSourceProtocol, +) + +from nemo_rl.data_plane.tq_token_sink import ( # noqa: E402 + STAGING_FIELDS, + TQTokenSink, + TQTokenSource, +) + +STAGING_PARTITION = "rollout_staging_test" + +pytestmark = pytest.mark.nemo_gym + + +@pytest.fixture() +def staging_partition(tq_client): + tq_client.register_partition( + partition_id=STAGING_PARTITION, + fields=list(STAGING_FIELDS), + num_samples=64, + consumer_tasks=["finalize"], + ) + yield STAGING_PARTITION + tq_client.clear_samples(sample_ids=None, partition_id=STAGING_PARTITION) + + +def test_implementations_satisfy_protocols(tq_client, staging_partition): + sink = TQTokenSink(tq_client, staging_partition=staging_partition) + source = TQTokenSource(tq_client, staging_partition=staging_partition) + assert isinstance(sink, TokenSinkProtocol) + assert isinstance(source, TokenSourceProtocol) + + +@pytest.mark.parametrize( + "fixture_name", ["worked_example", "single_call", "mixed_weight_versions"] +) +def test_tq_sink_source_passes_conformance(tq_client, staging_partition, fixture_name): + assert fixture_name in fixture_names() + sink = TQTokenSink(tq_client, staging_partition=staging_partition) + source = TQTokenSource(tq_client, staging_partition=staging_partition) + run_sink_source_conformance(load_fixture(fixture_name), sink, source) + + +def test_fetch_missing_key_raises_keyerror(tq_client, staging_partition): + source = TQTokenSource(tq_client, staging_partition=staging_partition) + with pytest.raises(KeyError): + source.fetch(["ghost_rollout/ghost_call"]) + + +def test_stage_failure_reports_not_raises(staging_partition): + class ExplodingClient: + def put_samples(self, **kwargs): + raise RuntimeError("controller down") + + sink = TQTokenSink(ExplodingClient(), staging_partition=staging_partition) + records, _, _, _ = build_fixture_artifacts(load_fixture("single_call")) + result = sink.stage(records[0]) + assert not result.ok + assert result.staging_key == records[0].staging_key + assert "controller down" in (result.error or "") + + +def test_sink_clear_drops_rows(tq_client, staging_partition): + sink = TQTokenSink(tq_client, staging_partition=staging_partition) + source = TQTokenSource(tq_client, staging_partition=staging_partition) + records, _, _, _ = build_fixture_artifacts(load_fixture("single_call")) + for record in records: + assert sink.stage(record).ok + keys = [record.staging_key for record in records] + assert len(source.fetch(keys)) == len(keys) + sink.clear(keys) + with pytest.raises(KeyError): + source.fetch(keys) diff --git a/tests/unit/experience/test_rollout_manager.py b/tests/unit/experience/test_rollout_manager.py index ee1f9921afd..3a4517241c7 100644 --- a/tests/unit/experience/test_rollout_manager.py +++ b/tests/unit/experience/test_rollout_manager.py @@ -73,16 +73,32 @@ class _FakeBuffer: def __init__(self) -> None: self.reserve_calls: list[int] = [] # weight_versions passed to reserve self.commit_calls: list[tuple[str, object, int, int]] = [] + self.abort_calls: list[str] = [] # reserve(weight_version=X) -> group_id; commit fills the slot. self._slots: list[str] = [] - def reserve(self, *, weight_version: int, group_id: str | None = None) -> str: + def reserve( + self, + *, + weight_version: int, + target_step: int | None = None, + group_id: str | None = None, + rollout_ids: list[str] | None = None, + ) -> str: + del target_step, rollout_ids if group_id is None: group_id = str(uuid.uuid4()) self.reserve_calls.append(weight_version) self._slots.append(group_id) return group_id + def abort(self, group_id: str) -> bool: + self.abort_calls.append(group_id) + if group_id in self._slots: + self._slots.remove(group_id) + return True + return False + async def commit( self, group_id: str, @@ -247,6 +263,37 @@ def test_requires_tq_buffer(self): with pytest.raises(AssertionError, match="tq_buffer"): _run(mgr.generate_and_push({"prompt": "p"})) + def test_failed_rollout_aborts_reserved_slot(self): + """A dispatch that raises must not leave a phantom unready slot.""" + + async def _boom(_input_sample): + raise RuntimeError("rollout exploded") + + buf = _FakeBuffer() + mgr = _make_manager(buf, _FakeImpl(on_run=_boom)) + + with pytest.raises(RuntimeError, match="rollout exploded"): + _run(mgr.generate_and_push({"prompt": "p"})) + + assert len(buf.reserve_calls) == 1 + assert buf.commit_calls == [] + assert len(buf.abort_calls) == 1 + assert buf._slots == [] # the reserved slot was dropped + + def test_failed_commit_aborts_reserved_slot(self): + """Commit failures (e.g. evicted slot) also abort the reservation.""" + + class _CommitBoomBuffer(_FakeBuffer): + async def commit(self, group_id, record, start_weight_version, end_weight_version): + raise ValueError("no live slot") + + buf = _CommitBoomBuffer() + mgr = _make_manager(buf, _FakeImpl()) + + with pytest.raises(ValueError, match="no live slot"): + _run(mgr.generate_and_push({"prompt": "p"})) + assert len(buf.abort_calls) == 1 + # --------------------------------------------------------------------------- # Tests for RolloutManager diff --git a/tests/unit/single_controller/test_tq_replay_buffer.py b/tests/unit/single_controller/test_tq_replay_buffer.py index 55b45c9eceb..6c586978478 100644 --- a/tests/unit/single_controller/test_tq_replay_buffer.py +++ b/tests/unit/single_controller/test_tq_replay_buffer.py @@ -322,3 +322,209 @@ def test_size_and_len(self): _run(buf.remove([0], remove_in_dp=True)) assert buf.size() == 1 assert len(buf) == 1 + + +class MultiPartitionFakeDataPlaneClient(FakeDataPlaneClient): + """Fake DP client that tracks rows per partition (token-capture mode).""" + + def __init__(self) -> None: + super().__init__(partition_id="rollout_data") + self.rows_by_partition: dict[str, dict[str, Any]] = {} + self.clear_calls_by_partition: list[tuple[str, list[str]]] = [] + + def put_samples(self, sample_ids, partition_id, fields=None, tags=None): + bucket = self.rows_by_partition.setdefault(partition_id, {}) + for i, sid in enumerate(sample_ids): + bucket[sid] = {"tag": dict(tags[i]) if tags is not None else {}} + return KVBatchMeta( + partition_id=partition_id, + task_name=None, + sample_ids=list(sample_ids), + fields=None, + tags=[dict(t) for t in tags] if tags is not None else None, + ) + + def clear_samples(self, sample_ids, partition_id): + ids = list(sample_ids) if sample_ids is not None else [] + self.clear_calls_by_partition.append((partition_id, ids)) + bucket = self.rows_by_partition.setdefault(partition_id, {}) + for sid in ids: + bucket.pop(sid, None) + + +class TestTQReplayBufferTokenCaptureMode: + """commit_finalized / abort / rollout_ids / staging-aware remove. + + All of these are uncalled on the legacy (token_capture.enabled=false) + path; the existing test classes above are the legacy-invariance guard. + """ + + def _make_capture_buffer(self, dp) -> TQReplayBuffer: + return TQReplayBuffer( + dp, + partition_id="rollout_data", + pad_value_dict={"token_ids": 0}, + staging_partition_id="rollout_staging", + ) + + def test_reserve_records_rollout_ids(self): + buf = self._make_capture_buffer(MultiPartitionFakeDataPlaneClient()) + buf.reserve(weight_version=1, rollout_ids=["g0_g0", "g0_g1"]) + assert buf._rollout_ids_list == [["g0_g0", "g0_g1"]] + # Legacy reserve records None. + buf.reserve(weight_version=1) + assert buf._rollout_ids_list[1] is None + + def test_commit_finalized_fills_slot_with_group_min_wv(self): + dp = MultiPartitionFakeDataPlaneClient() + buf = self._make_capture_buffer(dp) + group_id = buf.reserve(weight_version=4, rollout_ids=["r0", "r1"]) + # The finalizer published its own rows; commit_finalized only fills the slot. + meta = KVBatchMeta( + partition_id="rollout_data", + task_name=None, + sample_ids=[f"{group_id}_g0", f"{group_id}_g1"], + fields=None, + ) + _run( + buf.commit_finalized( + group_id, + meta, + group_min_wv=3, + group_max_wv=5, + staging_keys=["r0/c1", "r0/c2", "r1/c1"], + ) + ) + assert buf.ready_list == [True] + assert buf.start_weight_list == [3] # oldest call version, not reserve-time 4 + assert buf.end_weight_list == [5] + assert buf.meta_list[0] is meta + assert buf._staging_keys_list == [["r0/c1", "r0/c2", "r1/c1"]] + # No tensorize/put happened here. + assert dp.rows_by_partition.get("rollout_data") is None + + def test_commit_finalized_raises_for_evicted_slot(self): + buf = self._make_capture_buffer(MultiPartitionFakeDataPlaneClient()) + meta = KVBatchMeta( + partition_id="rollout_data", task_name=None, sample_ids=[], fields=None + ) + with pytest.raises(ValueError, match="no live slot"): + _run(buf.commit_finalized("ghost", meta, group_min_wv=0, group_max_wv=0)) + + def test_abort_drops_unready_slot_only(self): + dp = MultiPartitionFakeDataPlaneClient() + buf = self._make_capture_buffer(dp) + gid_unready = buf.reserve(weight_version=1) + gid_ready = buf.reserve(weight_version=1) + _run( + buf.commit( + gid_ready, + _make_record(), + start_weight_version=1, + end_weight_version=1, + ) + ) + assert buf.abort(gid_unready) is True + assert buf.size() == 1 + # Ready slots and unknown ids are not abortable. + assert buf.abort(gid_ready) is False + assert buf.abort("ghost") is False + assert buf.size() == 1 + + def test_remove_clears_staging_rows_alongside_canonical(self): + dp = MultiPartitionFakeDataPlaneClient() + buf = self._make_capture_buffer(dp) + group_id = buf.reserve(weight_version=1, rollout_ids=["r0"]) + meta = KVBatchMeta( + partition_id="rollout_data", + task_name=None, + sample_ids=[f"{group_id}_g0"], + fields=None, + ) + _run( + buf.commit_finalized( + group_id, + meta, + group_min_wv=1, + group_max_wv=1, + staging_keys=["r0/c1", "r0/c2"], + ) + ) + n = _run(buf.remove([0], remove_in_dp=True)) + assert n == 1 + assert ("rollout_data", [f"{group_id}_g0"]) in dp.clear_calls_by_partition + assert ("rollout_staging", ["r0/c1", "r0/c2"]) in dp.clear_calls_by_partition + + def test_remove_without_staging_partition_skips_staging_clear(self): + dp = MultiPartitionFakeDataPlaneClient() + buf = TQReplayBuffer( + dp, partition_id="rollout_data", pad_value_dict={"token_ids": 0} + ) + group_id = buf.reserve(weight_version=1) + meta = KVBatchMeta( + partition_id="rollout_data", + task_name=None, + sample_ids=[f"{group_id}_g0"], + fields=None, + ) + _run(buf.commit_finalized(group_id, meta, group_min_wv=1, group_max_wv=1)) + _run(buf.remove([0], remove_in_dp=True)) + partitions_cleared = {p for p, _ in dp.clear_calls_by_partition} + assert partitions_cleared == {"rollout_data"} + + +class TestTQReplayBufferEvictedCommit: + def test_commit_on_evicted_slot_writes_nothing(self): + """The pre-write check: an evicted group must not orphan rows.""" + dp = FakeDataPlaneClient() + buf = _make_buffer(dp) + group_id = buf.reserve(weight_version=1) + _run(buf.remove([0], remove_in_dp=False)) + + with pytest.raises(ValueError, match="no live slot"): + _run( + buf.commit( + group_id, + _make_record(), + start_weight_version=1, + end_weight_version=1, + ) + ) + assert dp.put_calls == [] + assert dp.depth() == 0 + + def test_commit_evicted_during_write_unwrites_rows(self): + """Eviction interleaving with the awaited put must clear the rows.""" + + class EvictDuringPut(FakeDataPlaneClient): + def __init__(self): + super().__init__() + self.buf: TQReplayBuffer | None = None + + async def put_samples( + self, sample_ids, partition_id, fields=None, tags=None + ): + result = FakeDataPlaneClient.put_samples( + self, sample_ids, partition_id, fields=fields, tags=tags + ) + # Simulate the sampler evicting the slot mid-write. + await self.buf.remove([0], remove_in_dp=False) + return result + + dp = EvictDuringPut() + buf = _make_buffer(dp) + dp.buf = buf + group_id = buf.reserve(weight_version=1) + + with pytest.raises(ValueError, match="evicted during"): + _run( + buf.commit( + group_id, + _make_record(), + start_weight_version=1, + end_weight_version=1, + ) + ) + # The written rows were un-written. + assert dp.depth() == 0 + assert len(dp.clear_calls) == 1 diff --git a/uv.lock b/uv.lock index 2fd51395111..3750f3a54a4 100644 --- a/uv.lock +++ b/uv.lock @@ -207,7 +207,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.13.5" +version = "3.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, @@ -218,12 +218,31 @@ dependencies = [ { name = "propcache", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "yarl", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/86/b7c870053e36a94e8951b803cb5b909bfbc9b90ca941527f5fcafbf6b0fa/aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090", size = 1732476, upload-time = "2026-03-31T21:58:18.925Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d2/e2f77eef1acb7111405433c707dc735e63f67a56e176e72e9e7a2cd3f493/aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665", size = 1754113, upload-time = "2026-03-31T21:58:27.624Z" }, - { url = "https://files.pythonhosted.org/packages/ec/a6/9b3e91eb8ae791cce4ee736da02211c85c6f835f1bdfac0594a8a3b7018c/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb", size = 1693205, upload-time = "2026-03-31T21:58:32.214Z" }, - { url = "https://files.pythonhosted.org/packages/01/a4/62f05a0a98d88af59d93b7fcac564e5f18f513cb7471696ac286db970d6a/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c", size = 1730356, upload-time = "2026-03-31T21:58:44.049Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/be/5afd201cc0ab139029aadb75392efe85a293403d9dd3a3226161c21ce00c/aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86", size = 506269, upload-time = "2026-07-23T01:54:49.075Z" }, + { url = "https://files.pythonhosted.org/packages/22/09/dec8189d62b45ade009f6792a2264b942a90cb88aeaf181239933cd72c3c/aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627", size = 515166, upload-time = "2026-07-23T01:54:51.894Z" }, + { url = "https://files.pythonhosted.org/packages/28/24/2854869d29ed8a8b19d74f9ec6629515f7e04d02dd329d9d179201e58e47/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82", size = 486263, upload-time = "2026-07-23T01:54:54.223Z" }, + { url = "https://files.pythonhosted.org/packages/d4/dd/57187c8be2a35aea65eaee3bd2c3dcbbcf0204f5106c89637e3610380cd1/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c", size = 492299, upload-time = "2026-07-23T01:54:56.236Z" }, + { url = "https://files.pythonhosted.org/packages/b9/11/06ae6ed8f0d414edf4068861e233d8fe23ee699bfd4b3ceb8663db948a62/aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f", size = 502235, upload-time = "2026-07-23T01:54:58.377Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a3/559639c34a345d2cf7c52dff6838119f2eaf29eb508227b5b83f573af813/aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80", size = 750883, upload-time = "2026-07-23T01:55:00.65Z" }, + { url = "https://files.pythonhosted.org/packages/91/cd/41e131f13afd1e7b0172a9d9eda085ef90eb8439f41f0d279db81ed3ae60/aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0", size = 508473, upload-time = "2026-07-23T01:55:02.945Z" }, + { url = "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf", size = 509190, upload-time = "2026-07-23T01:55:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/97/21/6464573e53d69672cc1eada3e5c5cb2d2efa82701e8305a0f2047a576967/aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd", size = 1761478, upload-time = "2026-07-23T01:55:07.383Z" }, + { url = "https://files.pythonhosted.org/packages/1a/81/d217043a4c17fbce360905e3b2bdd20139ebc9a2de836d035d179c4da006/aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807", size = 1735092, upload-time = "2026-07-23T01:55:09.803Z" }, + { url = "https://files.pythonhosted.org/packages/a1/66/e13a02d0eeb1a9a502402a977abb4e4abff9fe4051c26f80558c57a7c975/aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8", size = 1800546, upload-time = "2026-07-23T01:55:12.012Z" }, + { url = "https://files.pythonhosted.org/packages/26/5e/57d42fca1d18cb5acc1cad945d017fabc5d6ae71d8a08ad66be8dc3ee544/aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24", size = 1895250, upload-time = "2026-07-23T01:55:14.357Z" }, + { url = "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5", size = 1789289, upload-time = "2026-07-23T01:55:16.668Z" }, + { url = "https://files.pythonhosted.org/packages/cd/0f/cf16bcf56896981c1a0319f5d5db9337994b5165730c48a8fa07e9b34be6/aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4", size = 1586706, upload-time = "2026-07-23T01:55:18.913Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6f/76eac12a7f2480e1e304f842efdb07db33256b0d9165b866b6ef0806c202/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9", size = 1724652, upload-time = "2026-07-23T01:55:21.296Z" }, + { url = "https://files.pythonhosted.org/packages/39/b6/19c8c592baeeb94b75f966547d40c02ac7590902306ec5863d5c027cf506/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1", size = 1756239, upload-time = "2026-07-23T01:55:23.705Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c9/4e9383150296f97f873b680c4de8fb2cd88608fb9f48c79edcb111611abc/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371", size = 1769161, upload-time = "2026-07-23T01:55:26.082Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1e/147bdc6cc5de5f3ab011be8bf5d6e786633249f22c20bae06f85e45f5387/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde", size = 1578759, upload-time = "2026-07-23T01:55:28.846Z" }, + { url = "https://files.pythonhosted.org/packages/fd/31/78388a9d6040ece2e11df62ea229a822cf5e52d238374b220ae9975b2623/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e", size = 1792025, upload-time = "2026-07-23T01:55:31.457Z" }, + { url = "https://files.pythonhosted.org/packages/03/51/a3d29fdf2c25d796746af8ad6fe56a45d6256c38b0a8a2ed752e1160b3a2/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71", size = 1768477, upload-time = "2026-07-23T01:55:33.87Z" }, + { url = "https://files.pythonhosted.org/packages/29/a6/442e18b5afeade534d877a2dc3c3e392aff8d49787890b0cf84790410267/aiohttp-3.14.3-cp313-cp313-win32.whl", hash = "sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0", size = 451069, upload-time = "2026-07-23T01:55:36.121Z" }, + { url = "https://files.pythonhosted.org/packages/9d/69/3d876ac02659f271cf7f6769f14a8e3de5b6e888ed8b5a7e998086a4cec8/aiohttp-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883", size = 476518, upload-time = "2026-07-23T01:55:38.303Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0e/50d6e6471cd31edce8b282bdec59375a3a69124d8a989a0b1313355cae52/aiohttp-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2", size = 447676, upload-time = "2026-07-23T01:55:40.451Z" }, ] [[package]] @@ -238,6 +257,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/3b/40a68de458904bcc143622015fff2352b6461cd92fd66d3527bf1c6f5716/aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d", size = 25231, upload-time = "2025-03-31T14:16:18.478Z" }, ] +[[package]] +name = "aiohttp-retry" +version = "2.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608, upload-time = "2024-11-06T10:44:54.574Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981, upload-time = "2024-11-06T10:44:52.917Z" }, +] + [[package]] name = "aiosignal" version = "1.4.0" @@ -341,10 +372,12 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/6f/60/1e787a0b5ebf318483235be2a689ee367173983067e441b8379564f667c0/apache_tvm_ffi-0.1.9.tar.gz", hash = "sha256:d2d402587e8906de0a07f4746aa78f3d452c7efe3625d4bb39ac2ad693bce530", size = 2513731, upload-time = "2026-02-27T19:28:06.602Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/df/f2/b8c4b151169f6d7ba8773c8af68b2e0c1013d7fb3f1bdf87573f47157ce9/apache_tvm_ffi-0.1.9-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:49e52350b0470654847de752e65603b604a4d3323e7e9f5e8a982f44acc4c143", size = 2041756, upload-time = "2026-02-27T19:27:23.931Z" }, { url = "https://files.pythonhosted.org/packages/a7/c0/6d3d54f50012255b41bc3e24944c086f63c4707c8686c7c6780e9283eb96/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d503029e66c43b1a1cb1a42a1e9bb428c8a28dcbdec31c28e705472ca648a3a", size = 2203712, upload-time = "2026-02-27T19:27:25.867Z" }, { url = "https://files.pythonhosted.org/packages/c6/dd/2bab4c6cd86257dbf99e93452a1af833113f8dc3e25a25579f6e4e4c8a94/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28241371934ea8af10d5067087ba1229ebddded7b2c02d33a258ec2a96df8c46", size = 2299704, upload-time = "2026-02-27T19:27:27.477Z" }, { url = "https://files.pythonhosted.org/packages/7a/4a/b469bcb2e1014cb84d336d2a59f42958a058251c577a4c2680cacad346e2/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:87cacce81df55685fc6a76e1e3c5db1200e85e87bf5974b692c59d131b7bc622", size = 2130865, upload-time = "2026-02-27T19:27:29.092Z" }, { url = "https://files.pythonhosted.org/packages/70/ef/5402da5d37f5270fd88ea0348acca78dba9be8bdbf6c2bcae0935eb03ef1/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f45eb43499acac45ff6c93564f0ff2d3ca27b69656d540fd56ce59d51c0b4c65", size = 2278991, upload-time = "2026-02-27T19:27:30.729Z" }, + { url = "https://files.pythonhosted.org/packages/b5/23/1b7dc5f0807f83098183a57db6ee85b2c93b646d74a6e03781c9208aaeb0/apache_tvm_ffi-0.1.9-cp312-abi3-win_amd64.whl", hash = "sha256:d1dcf4c041d5ec05e3da1d545800c33cdbb95c113baa7705085ff79fa262752b", size = 1973200, upload-time = "2026-02-27T19:27:32.367Z" }, ] [[package]] @@ -360,10 +393,12 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/6d/3d/4b9226cd45aa800a6904603dda9b323d728f3c3869952a673f3483b78b19/apache_tvm_ffi-0.1.11.tar.gz", hash = "sha256:153cd2c5a9717804cb0bcd9b2709f22a1e5f80ed05b5a490faf5949b136eedba", size = 2798354, upload-time = "2026-05-04T17:48:43.852Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/05/9d/0f81ca556e5836b3ca64818cdae3f47dc7822bd35d22ddef7a54106d801d/apache_tvm_ffi-0.1.11-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:6ae51cc7df415b5f373a9df4baa1165a65608e519bea81e7dd23428f00eeb689", size = 2418793, upload-time = "2026-05-04T17:47:57.879Z" }, { url = "https://files.pythonhosted.org/packages/2a/a9/f48e5dd4ae1f6f0c5ffac259c0a9531b7d6a7c0a4c45bc2229d55de6adf8/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:da2c8d07fdc737d1ba75f4de25c29f156905b9dc980f1da90c395b4db525f522", size = 2605176, upload-time = "2026-05-04T17:47:59.676Z" }, { url = "https://files.pythonhosted.org/packages/36/99/2848df4e8ed5bf51df1d286d1718510584fa61e88adbc9c5b23d71b38f7c/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:78aa1857b04a2ea718317041ab3f01288b3d496e6036eb1b99ebdc9da0fdaef5", size = 2725887, upload-time = "2026-05-04T17:48:01.381Z" }, { url = "https://files.pythonhosted.org/packages/7d/80/963c991934a4eb0fa0c0178f51963333fe14a96b732009da642b6bf6b42e/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a8b845c8dff498fb981c1dda36c954549204191b485a385845e604966594d0b2", size = 2513121, upload-time = "2026-05-04T17:48:03.43Z" }, { url = "https://files.pythonhosted.org/packages/4d/18/95569107ee83619d61a3bb0d28743a0599f85c5161981e3e098c82c2b185/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2843f084cdc94dedacd8b257a395a2b71b8a3dc7fc99711b148bf1d161983128", size = 2697683, upload-time = "2026-05-04T17:48:05.222Z" }, + { url = "https://files.pythonhosted.org/packages/dc/99/f352cf1cce8f6f05584c4adf11de9eca07e6d217229bad6af35fb372926c/apache_tvm_ffi-0.1.11-cp312-abi3-win_amd64.whl", hash = "sha256:bd67e03759d25ff59f4e0ed9c8630a16872afc9dd8792f46ac3c927554015e60", size = 2365545, upload-time = "2026-05-04T17:48:07.295Z" }, ] [[package]] @@ -372,10 +407,21 @@ version = "0.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a9/9d/912fefab0e30aee6a3af8a62bbea4a81b29afa4ba2c973d31170620a26de/ast_serialize-0.3.0.tar.gz", hash = "sha256:1bc3ca09a63a021376527c4e938deedd11d11d675ce850e6f9c7487f5889992b", size = 60689, upload-time = "2026-04-30T23:24:48.104Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/93/72abad83966ed6235647c9f956417dc1e17e997696388521910e3d1fa3f4/ast_serialize-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ec2fafa5e4313cc8feed96e436ebe19ac7bc6fa41fbc2827e826c48b9e4c3a9", size = 1190024, upload-time = "2026-04-30T23:24:22.486Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/eb88584b2f0234e581762011208ca203252bf6c98e59b4769daa571f3576/ast_serialize-0.3.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef6d3c08b7b4cd29b48410338e134764a00e76d25841eb02c1084e868c888ecc", size = 1178633, upload-time = "2026-04-30T23:24:24.35Z" }, { url = "https://files.pythonhosted.org/packages/56/51/cf1ec1ff3e616373d0dcbd5fad502e0029dc541f13ab642259762a7d127f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d841424f41b886e98044abc80769c14a956e6e5ccd5fb5b0d9f5ead72be18a4", size = 1241351, upload-time = "2026-04-30T23:24:25.987Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/68fcf50478cf1093f2d423f034ae06453122c8b415d8e21a44668eca485d/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d21453734ad39367ede5d37efe4f59f830ce1c09f432fc72a90e368f77a4a3e7", size = 1239582, upload-time = "2026-04-30T23:24:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/9d/c1/a6c9fa284eceb5fc6f21347e968445a051d7ca2c4d34e6a04314646dbcee/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5e110cdce2a347e1dd987529c88ef54d26f67848dce3eba1b3b2cc2cf085c94", size = 1448853, upload-time = "2026-04-30T23:24:29.534Z" }, + { url = "https://files.pythonhosted.org/packages/23/5f/8ad3829a09e4e8c5328a53ce7d4711d660944e3e164c5f6abcc2c8f27167/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6e23a98e57560a055f5c4b68700a0fd5ce483d2814c23140b3638c7f5d1e61", size = 1262204, upload-time = "2026-04-30T23:24:31.482Z" }, { url = "https://files.pythonhosted.org/packages/25/13/44aa28d97f10e25247e8576b5f6b2795d4fa1a80acc88acc942c508d06f7/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c9e763d70293d65ce1e1ea8c943140c68d0953f0268c7ee0998f2e07f77dd0", size = 1266458, upload-time = "2026-04-30T23:24:33.088Z" }, + { url = "https://files.pythonhosted.org/packages/d8/58/b3a8be3777cd3744324fd5cec0d80d37cd96fc7cbb0fb010e03dff1e870f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4388a1796c228f1ce5c391426f7d21a0003ad3b47f677dbeded9bd1a85c7209f", size = 1308700, upload-time = "2026-04-30T23:24:34.657Z" }, { url = "https://files.pythonhosted.org/packages/13/03/f8312d6b57f5471a9dc7946f22b8798a1fc296d38c25766223aacadec42c/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5283cdcc0c64c3d8b9b688dc6aaa012d9c0cf1380a7f774a6bae6a1c01b3205a", size = 1416724, upload-time = "2026-04-30T23:24:36.562Z" }, + { url = "https://files.pythonhosted.org/packages/50/5d/13fc3789a7abac00559da2e2e9f386db4612aa1f84fc53d09bf714c37545/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f5ef88cc5842a5d7a6ac09dc0d5fc2c98f5d276c1f076f866d55047ce886785b", size = 1515441, upload-time = "2026-04-30T23:24:38.018Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b9/7ab43fc7a23b1f970281093228f5f79bed6edeed7a3e672bde6d7a832a58/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cc14bf402bdc0978594ecce783793de2c7470cd4f5cd7eb286ca97ed8ff7cba9", size = 1510522, upload-time = "2026-04-30T23:24:39.798Z" }, { url = "https://files.pythonhosted.org/packages/56/ec/d75fc2b788d319f1fad77c14156896f31afdfc68af85b505e5bdebcb9592/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11eae0cf1b7b3e0678133cc2daa974ea972caf02eb4b3aa062af6fa9acd52c57", size = 1460917, upload-time = "2026-04-30T23:24:41.305Z" }, + { url = "https://files.pythonhosted.org/packages/95/74/f99c81193a2725911e1911ae567ed27c2f2419332c7f3537366f9d238cac/ast_serialize-0.3.0-cp39-abi3-win32.whl", hash = "sha256:2db3dd99de5e6a5a11d7dda73de8750eb6e5baaf25245adf7bdcfe64b6108ae2", size = 1067804, upload-time = "2026-04-30T23:24:43.091Z" }, + { url = "https://files.pythonhosted.org/packages/16/81/76af00c47daa151e89f98ae21fbbcb2840aaa9f5766579c4da76a3c57188/ast_serialize-0.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:a2cd125adccf7969470621905d302750cd25951f22ea430d9a25b7be031e5549", size = 1105561, upload-time = "2026-04-30T23:24:44.578Z" }, + { url = "https://files.pythonhosted.org/packages/bd/46/d3ec57ad500f598d1554bd14ce4df615960549ab2844961bc4e1f5fbd174/ast_serialize-0.3.0-cp39-abi3-win_arm64.whl", hash = "sha256:0dd00da29985f15f50dc35728b7e1e7c84507bccfea1d9914738530f1c72238a", size = 1077165, upload-time = "2026-04-30T23:24:46.377Z" }, ] [[package]] @@ -423,10 +469,14 @@ version = "17.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/f0/8c8dca97ae0cf00e8e2a53bb5cb9aca5fd484f585ef3e9b412200aff3ebd/av-17.0.1.tar.gz", hash = "sha256:fbcbd4aa43bca6a8691816283112d1659a27f407bbeb66d1397023691339f5d4", size = 4411938, upload-time = "2026-04-18T17:12:34.29Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/82/e7007dcef7bd2d2c377e2e85977701384f42d19fc808c2ccb3a99eaf58f2/av-17.0.1-cp311-abi3-macosx_11_0_x86_64.whl", hash = "sha256:987f4f46ceae4da6c614dcbd2b8149be9dbf680c3bb7a6841c58af9cff4d9230", size = 23238802, upload-time = "2026-04-18T17:11:51.166Z" }, + { url = "https://files.pythonhosted.org/packages/6b/aa/858b09a08ea6f83f91be44b5a5adad13ae8d9ac8b80fda27e73c24bfb160/av-17.0.1-cp311-abi3-macosx_14_0_arm64.whl", hash = "sha256:d97f54e55b18a74912f479c1978aadd1341d38d892dee95bb5c2f2dccfa72f32", size = 18709338, upload-time = "2026-04-18T17:11:53.286Z" }, { url = "https://files.pythonhosted.org/packages/a8/8b/8de3fd21c4b0b74d44337421abeab0e71462337fb6a28fff888e0c356cbd/av-17.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e6eee84afa48d0e9321047cd3e4facd44b401493f6bdc753e2e1d1e7c9e6d13e", size = 34007351, upload-time = "2026-04-18T17:11:56.116Z" }, { url = "https://files.pythonhosted.org/packages/02/28/167b291356c2cc315a2d62a95b0ceace72b5b0bf547de30b89313110f032/av-17.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c58c71bffd9383908c85695ac61d3184c668accb04a5bd1b262e0fb8d09f60a5", size = 36345295, upload-time = "2026-04-18T17:11:59.125Z" }, { url = "https://files.pythonhosted.org/packages/04/fa/aae56f2ff2c204c408641e1120f5ca5ce9c3390cf5362245c6f1158704b5/av-17.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:42d6745d30a410ec9b22aef79a52a7ab5a001eb8f5adfd952946606a30983318", size = 35183754, upload-time = "2026-04-18T17:12:01.697Z" }, { url = "https://files.pythonhosted.org/packages/ba/bd/776046f27093aef80155a204ca7d82a887ae4ee72ba4ef8411b46ea7898c/av-17.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3ed6bcd7021fe55832f95b8ef78dd01a4cb21faf3cd71f1e1bf4f20bf100b278", size = 37430809, upload-time = "2026-04-18T17:12:04.231Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d5/3261bd2c6b7f6c0aa8379fc970d1ecf496330990b992ad28607785074268/av-17.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:9af524e8632a54032e361d6b88895bd3e7c6212ca560de60f5ccc525323c764c", size = 28889649, upload-time = "2026-04-18T17:12:07.04Z" }, + { url = "https://files.pythonhosted.org/packages/98/39/381104e427a0c7231d2ec0d25d538d58fc20fc0458846b95860d3ef8073b/av-17.0.1-cp311-abi3-win_arm64.whl", hash = "sha256:50e58a473d65ea29b645e45c9fd8518a6783737135683ecc40571a91592bdfe4", size = 21918412, upload-time = "2026-04-18T17:12:09.312Z" }, ] [[package]] @@ -451,20 +501,45 @@ 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 = "bidict" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093, upload-time = "2024-02-18T19:09:05.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, +] + [[package]] name = "blake3" version = "1.0.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/75/aa/abcd75e9600987a0bc6cfe9b6b2ff3f0e2cb08c170addc6e76035b5c4cb3/blake3-1.0.8.tar.gz", hash = "sha256:513cc7f0f5a7c035812604c2c852a0c1468311345573de647e310aca4ab165ba", size = 117308, upload-time = "2025-10-14T06:47:48.83Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/55/b8/11de9528c257f7f1633f957ccaff253b706838d22c5d2908e4735798ec01/blake3-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:46dc20976bd6c235959ef0246ec73420d1063c3da2839a9c87ca395cf1fd7943", size = 347771, upload-time = "2025-10-14T06:46:04.248Z" }, + { url = "https://files.pythonhosted.org/packages/50/26/f7668be55c909678b001ecacff11ad7016cd9b4e9c7cc87b5971d638c5a9/blake3-1.0.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d17eb6382634b3a5bc0c0e0454d5265b0becaeeadb6801ed25150b39a999d0cc", size = 325431, upload-time = "2025-10-14T06:46:06.136Z" }, { url = "https://files.pythonhosted.org/packages/77/57/e8a85fa261894bf7ce7af928ff3408aab60287ab8d58b55d13a3f700b619/blake3-1.0.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19fc6f2b7edab8acff6895fc6e38c19bd79f4c089e21153020c75dfc7397d52d", size = 370994, upload-time = "2025-10-14T06:46:07.398Z" }, + { url = "https://files.pythonhosted.org/packages/62/cd/765b76bb48b8b294fea94c9008b0d82b4cfa0fa2f3c6008d840d01a597e4/blake3-1.0.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f54cff7f15d91dc78a63a2dd02a3dccdc932946f271e2adb4130e0b4cf608ba", size = 374372, upload-time = "2025-10-14T06:46:08.698Z" }, + { url = "https://files.pythonhosted.org/packages/36/7a/32084eadbb28592bb07298f0de316d2da586c62f31500a6b1339a7e7b29b/blake3-1.0.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7e12a777f6b798eb8d06f875d6e108e3008bd658d274d8c676dcf98e0f10537", size = 447627, upload-time = "2025-10-14T06:46:10.002Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f4/3788a1d86e17425eea147e28d7195d7053565fc279236a9fd278c2ec495e/blake3-1.0.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddfc59b0176fb31168f08d5dd536e69b1f4f13b5a0f4b0c3be1003efd47f9308", size = 507536, upload-time = "2025-10-14T06:46:11.614Z" }, + { url = "https://files.pythonhosted.org/packages/fe/01/4639cba48513b94192681b4da472cdec843d3001c5344d7051ee5eaef606/blake3-1.0.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2336d5b2a801a7256da21150348f41610a6c21dae885a3acb1ebbd7333d88d8", size = 394105, upload-time = "2025-10-14T06:46:12.808Z" }, { url = "https://files.pythonhosted.org/packages/21/ae/6e55c19c8460fada86cd1306a390a09b0c5a2e2e424f9317d2edacea439f/blake3-1.0.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4072196547484c95a5a09adbb952e9bb501949f03f9e2a85e7249ef85faaba8", size = 386928, upload-time = "2025-10-14T06:46:16.284Z" }, { url = "https://files.pythonhosted.org/packages/ee/6c/05b7a5a907df1be53a8f19e7828986fc6b608a44119641ef9c0804fbef15/blake3-1.0.8-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0eab3318ec02f8e16fe549244791ace2ada2c259332f0c77ab22cf94dfff7130", size = 550003, upload-time = "2025-10-14T06:46:17.791Z" }, { url = "https://files.pythonhosted.org/packages/b4/03/f0ea4adfedc1717623be6460b3710fcb725ca38082c14274369803f727e1/blake3-1.0.8-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a33b9a1fb6d1d559a8e0d04b041e99419a6bb771311c774f6ff57ed7119c70ed", size = 553857, upload-time = "2025-10-14T06:46:19.088Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6f/e5410d2e2a30c8aba8389ffc1c0061356916bf5ecd0a210344e7b69b62ab/blake3-1.0.8-cp313-cp313-win32.whl", hash = "sha256:e171b169cb7ea618e362a4dddb7a4d4c173bbc08b9ba41ea3086dd1265530d4f", size = 228315, upload-time = "2025-10-14T06:46:20.391Z" }, + { url = "https://files.pythonhosted.org/packages/79/ef/d9c297956dfecd893f29f59e7b22445aba5b47b7f6815d9ba5dcd73fcae6/blake3-1.0.8-cp313-cp313-win_amd64.whl", hash = "sha256:3168c457255b5d2a2fc356ba696996fcaff5d38284f968210d54376312107662", size = 215477, upload-time = "2025-10-14T06:46:21.542Z" }, + { url = "https://files.pythonhosted.org/packages/20/ba/eaa7723d66dd8ab762a3e85e139bb9c46167b751df6e950ad287adb8fb61/blake3-1.0.8-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:b4d672c24dc15ec617d212a338a4ca14b449829b6072d09c96c63b6e6b621aed", size = 347289, upload-time = "2025-10-14T06:46:22.772Z" }, + { url = "https://files.pythonhosted.org/packages/47/b3/6957f6ee27f0d5b8c4efdfda68a1298926a88c099f4dd89c711049d16526/blake3-1.0.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:1af0e5a29aa56d4fba904452ae784740997440afd477a15e583c38338e641f41", size = 324444, upload-time = "2025-10-14T06:46:24.729Z" }, { url = "https://files.pythonhosted.org/packages/13/da/722cebca11238f3b24d3cefd2361c9c9ea47cfa0ad9288eeb4d1e0b7cf93/blake3-1.0.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef153c5860d5bf1cc71aece69b28097d2a392913eb323d6b52555c875d0439fc", size = 370441, upload-time = "2025-10-14T06:46:26.29Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d5/2f7440c8e41c0af995bad3a159e042af0f4ed1994710af5b4766ca918f65/blake3-1.0.8-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e8ae3689f0c7bfa6ce6ae45cab110e4c3442125c4c23b28f1f097856de26e4d1", size = 374312, upload-time = "2025-10-14T06:46:27.451Z" }, + { url = "https://files.pythonhosted.org/packages/a6/6c/fb6a7812e60ce3e110bcbbb11f167caf3e975c589572c41e1271f35f2c41/blake3-1.0.8-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb83532f7456ddeb68dae1b36e1f7c52f9cb72852ac01159bbcb1a12b0f8be0", size = 447007, upload-time = "2025-10-14T06:46:29.056Z" }, + { url = "https://files.pythonhosted.org/packages/13/3b/c99b43fae5047276ea9d944077c190fc1e5f22f57528b9794e21f7adedc6/blake3-1.0.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ae7754c7d96e92a70a52e07c732d594cf9924d780f49fffd3a1e9235e0f5ba7", size = 507323, upload-time = "2025-10-14T06:46:30.661Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bb/ba90eddd592f8c074a0694cb0a744b6bd76bfe67a14c2b490c8bdfca3119/blake3-1.0.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bacaae75e98dee3b7da6c5ee3b81ee21a3352dd2477d6f1d1dbfd38cdbf158a", size = 393449, upload-time = "2025-10-14T06:46:31.805Z" }, { url = "https://files.pythonhosted.org/packages/25/ed/58a2acd0b9e14459cdaef4344db414d4a36e329b9720921b442a454dd443/blake3-1.0.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9456c829601d72852d8ba0af8dae0610f7def1d59f5942efde1e2ef93e8a8b57", size = 386844, upload-time = "2025-10-14T06:46:33.195Z" }, { url = "https://files.pythonhosted.org/packages/4a/04/fed09845b18d90862100c8e48308261e2f663aab25d3c71a6a0bdda6618b/blake3-1.0.8-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:497ef8096ec4ac1ffba9a66152cee3992337cebf8ea434331d8fd9ce5423d227", size = 549550, upload-time = "2025-10-14T06:46:35.23Z" }, { url = "https://files.pythonhosted.org/packages/d6/65/1859fddfabc1cc72548c2269d988819aad96d854e25eae00531517925901/blake3-1.0.8-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:511133bab85ff60ed143424ce484d08c60894ff7323f685d7a6095f43f0c85c3", size = 553805, upload-time = "2025-10-14T06:46:36.532Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c7/2969352017f62378e388bb07bb2191bc9a953f818dc1cd6b9dd5c24916e1/blake3-1.0.8-cp313-cp313t-win32.whl", hash = "sha256:9c9fbdacfdeb68f7ca53bb5a7a5a593ec996eaf21155ad5b08d35e6f97e60877", size = 228068, upload-time = "2025-10-14T06:46:37.826Z" }, + { url = "https://files.pythonhosted.org/packages/d8/fc/923e25ac9cadfff1cd20038bcc0854d0f98061eb6bc78e42c43615f5982d/blake3-1.0.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3cec94ed5676821cf371e9c9d25a41b4f3ebdb5724719b31b2749653b7cc1dfa", size = 215369, upload-time = "2025-10-14T06:46:39.054Z" }, ] [[package]] @@ -491,6 +566,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ed/4d/1392562369b1139e741b30d624f09fe7091d17dd5579fae5732f044b12bb/blobfile-3.0.0-py3-none-any.whl", hash = "sha256:48ecc3307e622804bd8fe13bf6f40e6463c4439eba7a1f9ad49fd78aa63cc658", size = 75413, upload-time = "2024-08-27T00:02:51.518Z" }, ] +[[package]] +name = "boto3" +version = "1.43.57" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "jmespath", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "s3transfer", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/30/324319a914752e4021358ccf8252c04364eb8358f9d41d9c3f021959b363/boto3-1.43.57.tar.gz", hash = "sha256:549c95e45f9b04cf0c69727632dbdda23b84dcd3d0ed7981c6aaff72ef9cb5af", size = 112690, upload-time = "2026-07-27T19:31:09.32Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/a4/2c4ee25556a997a81ea01073962cf8351da3707412c584d053b3861d09e8/boto3-1.43.57-py3-none-any.whl", hash = "sha256:115ed9cac409d9b57e2437b52fdb4286660d12a2bd44a0f48d530e68623d09a7", size = 140028, upload-time = "2026-07-27T19:31:07.226Z" }, +] + +[[package]] +name = "botocore" +version = "1.43.57" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "urllib3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/92/1f8a454cf90bcb0c0e32a25817441cb7f3702fdd76710d7018abad12a2fc/botocore-1.43.57.tar.gz", hash = "sha256:001a5653bebc03b862bde2da63bad4adb0b30072a3f247aba4daae5aa097b546", size = 15739550, upload-time = "2026-07-27T19:30:57.916Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl", hash = "sha256:319c6d79f66c3f3f2b538f7dcdc90e410a15a7bfced1db06479134947e629482", size = 15424433, upload-time = "2026-07-27T19:30:55.08Z" }, +] + [[package]] name = "build" version = "1.5.0" @@ -529,10 +632,14 @@ version = "6.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/be/db/810437bcfe13cf5e09b68bad1ce57c8fa04ca9272c68946bbf2f4fa522c8/cbor2-6.1.1.tar.gz", hash = "sha256:6f0644869e0fdcd6f3874330b8f1cebd009f33191de43acf609dc2409cd362c4", size = 86297, upload-time = "2026-05-14T10:57:42.231Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/ec/30a52d7f6844cefd37601311a226d091268564a47b0dac56bc0469573681/cbor2-6.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f027e077345ba7d1a88cbed9168196e77f5ce8e8c816305bb1c7a2e4894bddf", size = 409070, upload-time = "2026-05-14T10:57:05.843Z" }, { url = "https://files.pythonhosted.org/packages/b7/a5/653193249a64ca46def52798e8f10ddbc918f11818a977b2aa7248062520/cbor2-6.1.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:559025ad8e1f9f5d019a40dc8f14f43c111c11207b4dde852e943a3002b43ec0", size = 453218, upload-time = "2026-05-14T10:57:07.6Z" }, { url = "https://files.pythonhosted.org/packages/9f/79/bdcb9d43ed537abaa89e662d6340244207ec85b6e66e3bd7f40856c3a5d4/cbor2-6.1.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a6690f7df210386866e120475183132df98f77bf6df624097f66e3214e775084", size = 466244, upload-time = "2026-05-14T10:57:09.297Z" }, { url = "https://files.pythonhosted.org/packages/9c/44/fe0543996d53538c074f8ee18f7391b5458c528b1717740d750a9e472e1d/cbor2-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f4898b5463a567775a05310407dbea5b4a8d7ae8e81337ae9084f5fe226938ff", size = 520804, upload-time = "2026-05-14T10:57:10.682Z" }, { url = "https://files.pythonhosted.org/packages/cd/83/577bbafef3bc887d654a73f3f4ab11e1bd5320abd9108bfc51fbea1498a8/cbor2-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf3ef1fae6f14081a15f178e933ab846d3181f059ee4090975518b71f58bb09f", size = 533598, upload-time = "2026-05-14T10:57:12.098Z" }, + { url = "https://files.pythonhosted.org/packages/57/32/c1c9f435b109ded86ef2e90ff73b95624c84c6edf01489941363a6069725/cbor2-6.1.1-cp313-cp313-win32.whl", hash = "sha256:4642780d27c0b411f4669fcb82e0d7a6b93a0c41c03a0c51296fd6f6858f63fa", size = 281738, upload-time = "2026-05-14T10:57:13.614Z" }, + { url = "https://files.pythonhosted.org/packages/4d/39/9232731f161b2dfe2dc28b06bbacfc2b6a85f1255bf58ebc578ae760ef38/cbor2-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:616bc0538095860fe5607cc06d7b2de3e261a6caccd01ff3f1d4a4a9ad29adbf", size = 300018, upload-time = "2026-05-14T10:57:15.021Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c2/67f2e3a83acfcecad947784bb1590d1978662b5472fcbf7d73e219813456/cbor2-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:7b193d2d024bb5d037e613272f5e436d53f02301101f0ce3916117688643181f", size = 287823, upload-time = "2026-05-14T10:57:16.525Z" }, ] [[package]] @@ -553,10 +660,18 @@ dependencies = [ ] 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/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]] @@ -574,10 +689,22 @@ version = "3.4.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] @@ -686,14 +813,28 @@ dependencies = [ ] 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/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" }, ] [[package]] @@ -702,14 +843,36 @@ version = "7.14.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/23/7f/d0720730a397a999ffc0fd3f5bebef347338e3a47b727da66fbb228e2ff2/coverage-7.14.0.tar.gz", hash = "sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74", size = 919489, upload-time = "2026-05-10T18:02:31.397Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/76/b7c66ee3c66e1b0f9d894c8125983aa0c03fb2336f2fd16559f9c966157f/coverage-7.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f2bbb8254370eb4c628ff3d6fa8a7f74ddc40565394d4f7ab791d1fe568e37ef", size = 219990, upload-time = "2026-05-10T18:00:38.887Z" }, + { url = "https://files.pythonhosted.org/packages/b3/af/e567cbad5ba69c013a50146dfa886dc7193361fda77521f51274ff620e1b/coverage-7.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23b81107f46d3f21d0cbce30664fcec0f5d9f585638a67081750f99738f6bf66", size = 220365, upload-time = "2026-05-10T18:00:40.864Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/9ad575d505b4d805b254febc8a5b338a2efe278f8786e56ff1cb8413f9c3/coverage-7.14.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:22a7e06a5f11a757cdfe79018e9095f9f69ae283c5cd8123774c788deec8717b", size = 251363, upload-time = "2026-05-10T18:00:42.489Z" }, { url = "https://files.pythonhosted.org/packages/6f/5f/b5370068b2f57787454592ed7dcd1002f0f1703b7db1fa30f6a325a4ca6e/coverage-7.14.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9d1aa57a1dc8e05bdc42e81c5d671d849577aeedf279f4c449d6d286f9ed88ca", size = 253961, upload-time = "2026-05-10T18:00:44.079Z" }, { url = "https://files.pythonhosted.org/packages/29/1e/51adf17738976e8f2b85ddef7b7aa12a0838b056c92f175941d8862767c1/coverage-7.14.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90c1a51bcfddf645b3bb7ec333d9e94393a8e94f55642380fa8a9a5a9e636cb7", size = 255193, upload-time = "2026-05-10T18:00:45.623Z" }, + { url = "https://files.pythonhosted.org/packages/9e/7b/5bfd7ac1df3b881c2ac7a5cbc99c7609e6296c402f5ef587cd81c6f355b3/coverage-7.14.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a841fae2fadcae4f438d43b6ccc4aac2ad609f47cdb6cfdce60cbb3fe5ca7bc2", size = 257326, upload-time = "2026-05-10T18:00:47.173Z" }, + { url = "https://files.pythonhosted.org/packages/7d/38/1d37d316b174fad3843a1d76dbdfe4398771c9ecd0515935dd9ece9cd627/coverage-7.14.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c79d2319cabef1fe8e86df73371126931550804738f78ad7d31e3aad85a67367", size = 251582, upload-time = "2026-05-10T18:00:49.152Z" }, { url = "https://files.pythonhosted.org/packages/34/46/746704f95980ba220214e1a41e18cec5aea80a898eaa53c51bf2d645ff36/coverage-7.14.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b23b0c6f0b1db6ad769b7050c8b641c0bf215ded26c1816955b17b7f26edfa9", size = 253325, upload-time = "2026-05-10T18:00:51.252Z" }, + { url = "https://files.pythonhosted.org/packages/e1/b9/bbe87206d9687b192352f893797825b5f5b15ecd3aa9c68fbff0c074d77b/coverage-7.14.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:55d3089079ce181a4566b1065ab28d2575eb76d8ac8f81f4fcda2bf037fee087", size = 251291, upload-time = "2026-05-10T18:00:52.816Z" }, + { url = "https://files.pythonhosted.org/packages/46/57/b8cdb12ac0d73ef0243218bd5e22c9df8f92edab8018213a86aec67c5324/coverage-7.14.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:49c005cba1e2f9677fb2845dcdf9a2e72a52a17d63e8231aaaae35d9f50215ef", size = 255448, upload-time = "2026-05-10T18:00:54.548Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d4/5002019538b2036ce3c84340f54d2fd5100d55b0a6b0894eee56128d03c7/coverage-7.14.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9117377b823daa28aa8635fbb08cda1cd6be3d7143257345459559aeef852d52", size = 251110, upload-time = "2026-05-10T18:00:56.122Z" }, { url = "https://files.pythonhosted.org/packages/37/53/20c5009477660f084e6ed60bc02a91894b8e234e617e86ecfd9aaf78e27b/coverage-7.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7b79d646cf46d5cf9a9f40281d4441df5849e445726e369006d2b117710b33fe", size = 252885, upload-time = "2026-05-10T18:00:57.967Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ab/3cf6427ac9c1f1db747dbb1ce71dde47984876d4c2cfd018a3fef0a78d4d/coverage-7.14.0-cp313-cp313-win32.whl", hash = "sha256:fb609b3658479e33f9516d46f1a89dbb9b6c261366e3a11844a96ec487533dae", size = 222539, upload-time = "2026-05-10T18:00:59.581Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b8/9228523e80321c2cb4880d1f589bc0171f2f71432c35118ad04dc01decce/coverage-7.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0773d8329cf32b6fd222e4b52622c61fe8d503eb966cfc8d3c3c10c96266d50e", size = 223344, upload-time = "2026-05-10T18:01:01.531Z" }, + { url = "https://files.pythonhosted.org/packages/a3/99/118daa192f95e3a6cb2740100fbf8797cda1734b4134ef0b5d501a7fa8f3/coverage-7.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:b4e26a0f1b696faf283bffe5b8569e44e336c582439df5d53281ab89ee0cba96", size = 221966, upload-time = "2026-05-10T18:01:03.16Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f1/a46cc0c013be170216253184a32366d7cbdb9252feaec866b05c2d12a894/coverage-7.14.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:953f521ca9445300397e65fda3dca58b2dbd68fee983777420b57ac3c77e9f90", size = 220679, upload-time = "2026-05-10T18:01:05.058Z" }, + { url = "https://files.pythonhosted.org/packages/64/8c/9c30a3d311a34177fa432995be7fbfc64477d8bac5630bd38055b1c9b424/coverage-7.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:98af83fd65ae24b1fdd03aaead967a9f523bcd2f1aab2d4f3ffda65bb568a6f1", size = 221033, upload-time = "2026-05-10T18:01:07.002Z" }, + { url = "https://files.pythonhosted.org/packages/9a/cd/3fb5e06c3badefd0c1b47e2044fdca67f8220a4ec2e7fcfb476aa0a67c6c/coverage-7.14.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:668b92e6958c4db7cf92e81caac328dfbbdbb215db2850ad28f0cbe1eea0bfbd", size = 262333, upload-time = "2026-05-10T18:01:08.903Z" }, { url = "https://files.pythonhosted.org/packages/a8/e6/fbc322325c7294d3e22c1ad6b79e45d0806b25228c8e5842aed6d8169aa7/coverage-7.14.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9fbd898551762dea00d3fef2b1c4f99afd2c6a3ff952ea07d60a9bd5ed4f34bc", size = 264410, upload-time = "2026-05-10T18:01:10.531Z" }, { url = "https://files.pythonhosted.org/packages/08/92/c497b264bec1673c47cc77e26f760fcda4654cabf1f39546d1a23a3b8c35/coverage-7.14.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68af363c07ecd8d4b7d4043d85cb376d7d227eceb54e5323ee45da73dbd3e426", size = 266836, upload-time = "2026-05-10T18:01:12.19Z" }, + { url = "https://files.pythonhosted.org/packages/78/fc/045da320987f401af5d2815d351e8aa799aec859f60e29f445e3089eeedb/coverage-7.14.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e57054a583da8ac55edf24117ea4c9133032cfc4cf72aa2d48c1e5d4b52f899", size = 267974, upload-time = "2026-05-10T18:01:13.926Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ae/227b1e379497fb7a4fc3286e620f80c8a1e7cec66d45695a01639eb1af65/coverage-7.14.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3499459bbcdd51a65b64c35ab7ed2764eaf3cba826e0df3f1d7fe2e102b70b", size = 261578, upload-time = "2026-05-10T18:01:15.564Z" }, { url = "https://files.pythonhosted.org/packages/a0/f5/3570342900f2acea31d33ff1590c5d8bac1a8e1a2e1c6d34a5d5e61de681/coverage-7.14.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:45899ec2138a4346ed34d601dedf5076fb74edf2d1dd9dc76a78e82397edee90", size = 264394, upload-time = "2026-05-10T18:01:17.607Z" }, + { url = "https://files.pythonhosted.org/packages/16/29/de1bbc01c935b28f89b1dc3db85b011c055e843a8e5e3b83141c3f80af7f/coverage-7.14.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8767486808c436f05b23ab98eb963fb29185e32a9357a166971685cb3459900f", size = 262022, upload-time = "2026-05-10T18:01:19.304Z" }, + { url = "https://files.pythonhosted.org/packages/35/95/f53890b0bf2fc10ab168e05d38869215e73ca24c4cb521c3bb0eb62fe16b/coverage-7.14.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a3b5ddfd6aa7ddad53ee3edb231e88a2151507a43229b7d71b953916deca127d", size = 265732, upload-time = "2026-05-10T18:01:21.494Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ea/c919e259081dd2bdf0e43b87209709ba7ec2e4117c2a7f5185379c43463c/coverage-7.14.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:63df0fe568e698e1045792399f8ab6da3a6c2dce3182813fb92afa2641087b47", size = 260921, upload-time = "2026-05-10T18:01:23.533Z" }, { url = "https://files.pythonhosted.org/packages/1a/2c/c2831889705a81dc5d1c6ca12e4d8e9b95dfc146d153488a6c0ea685d28e/coverage-7.14.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:827d6397dbd95144939b18f89edf31f63e1f99633e8d5f32f22ba8bdda567477", size = 263109, upload-time = "2026-05-10T18:01:25.165Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a9/2fcae5003cac3d63fe344d2166243c2756935f48420863c5272b240d550b/coverage-7.14.0-cp313-cp313t-win32.whl", hash = "sha256:7bf43e000d24012599b879791cff41589af90674722421ef11b11a5431920bab", size = 223212, upload-time = "2026-05-10T18:01:27.157Z" }, + { url = "https://files.pythonhosted.org/packages/3f/bb/18e94d7b14b9b398164197114a587a04ab7c9fdbe1d237eef57311c5e883/coverage-7.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3f5549365af25d770e06b1f8f5682d9a5637d06eb494db91c6fa75d3950cc917", size = 224272, upload-time = "2026-05-10T18:01:29.107Z" }, + { url = "https://files.pythonhosted.org/packages/db/56/4f14fad782b035c81c4ffd09159e7103d42bb1d93ac8496d04b90a11b7da/coverage-7.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6d160217ec6fe890f16ad3a9531761589443749e448f91986c972714fad361c8", size = 222530, upload-time = "2026-05-10T18:01:31.151Z" }, { url = "https://files.pythonhosted.org/packages/61/e8/cb8e80d6f9f55b99588625062822bf946cf03ed06315df4bd8397f5632a1/coverage-7.14.0-py3-none-any.whl", hash = "sha256:8de5b61163aee3d05c8a2beab6f47913df7981dad1baf82c414d99158c286ab1", size = 211764, upload-time = "2026-05-10T18:02:29.538Z" }, ] @@ -722,22 +885,34 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" }, { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, + { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" }, + { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" }, { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, + { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" }, ] [[package]] @@ -750,8 +925,10 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/36/41ccc303eb6be8ae82c5edd2ccae938876e8a794660e8bb96a193174a978/cuda_bindings-13.0.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb16a7f769c9c67469add7a1d9f6c14dd44637f6921cb6b9eb82cb5015b35c3d", size = 11537064, upload-time = "2025-10-21T15:09:07.84Z" }, { url = "https://files.pythonhosted.org/packages/ab/ac/699889100536f1b63779646291e74eefa818087a0974eb271314d850f5dc/cuda_bindings-13.0.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:512d0d803a5e47a8a42d5a34ce0932802bf72fe952fdb11ac798715a35c6e5cb", size = 11910447, upload-time = "2025-10-21T15:09:09.942Z" }, + { url = "https://files.pythonhosted.org/packages/8c/f9/a2f5910aaf21f4cd43f456ea80f47f1424eece5b8f063dac1980304b8ef0/cuda_bindings-13.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:dd83e8d79587e265b82d3e589ba6b061770537443dfb1bb4a74f755c8b13f62b", size = 11211659, upload-time = "2025-10-21T15:09:12.639Z" }, { url = "https://files.pythonhosted.org/packages/11/67/9656e003f18c5b32e1a2496998b24f4355ec978c5f3639b0eb9f6d0ff83f/cuda_bindings-13.0.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c859e326c776a47e66c50386a10c84fe34291eb6e711610c9fd7cc27d446334f", size = 11522409, upload-time = "2025-10-21T15:09:14.674Z" }, { url = "https://files.pythonhosted.org/packages/18/d8/a83379caa7c1bed4195e704c24467a6c07fe8e29c7055ccd4f00c5702363/cuda_bindings-13.0.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e675dbd009fb5e66d63fd13a8ff35f849120f01bcc4dafadbced3004605c3588", size = 11903148, upload-time = "2025-10-21T15:09:16.918Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e0/ff1eeda06364df8c750843432ac6efb33a06df38261f0a1ceee59bb7dac2/cuda_bindings-13.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:193762306b6032c00a141fc38bcef92c6fb4d332fd2d6a550c7f950e7fd8acd8", size = 11543153, upload-time = "2025-10-21T15:09:19.252Z" }, ] [[package]] @@ -765,6 +942,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/98/ff82ac290e93c771639fd73ba9b37937a97f028169f3e8c121fc258eaca7/cuda_core-0.7.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f25a3042a73dcaa8046a7fa3b0ba9b3de15a39a05b77483dc0a8281bd182716e", size = 29873257, upload-time = "2026-04-08T17:03:26.138Z" }, { url = "https://files.pythonhosted.org/packages/61/21/99169dc3aa66d8fc3eaae7b69fbeaa57a672a71586364069211b7e57e08c/cuda_core-0.7.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52d11f599ec5af622da0b7cf28506978e382aa614f8552edaddbf21bcda6c7a6", size = 30368143, upload-time = "2026-04-08T17:03:29.331Z" }, + { url = "https://files.pythonhosted.org/packages/67/23/0ae61d9e0c78208e97c9b2b274026dead3a46034a3db24ec4568e3cda1d7/cuda_core-0.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:b4dd7c2b2d9f95acbffc9df62bd52d4bcdab72b7780fc3bd7e691e1e0cc1f071", size = 4076762, upload-time = "2026-04-08T17:03:32.059Z" }, ] [[package]] @@ -796,6 +974,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/7d/ee943554f83d6a143d9e0a5cf27cd7f5f8f6ef447c7e8366d9ad6a5d1bf2/cuda_tile-1.3.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:8a9bd4dae193cddf438f55d617b6f25b4b0b0fcf4ac4acde7d2695898e396c30", size = 245750, upload-time = "2026-04-20T15:52:12.91Z" }, { url = "https://files.pythonhosted.org/packages/35/20/e1daea2dc4e094290ba727750f8342095ae857ff3ba4f81c489f48688613/cuda_tile-1.3.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:a44a81e255fdb7bf8e1f7511fe3a019e6045024574509ea8548e0f71f25f8473", size = 247300, upload-time = "2026-04-20T15:51:03.072Z" }, + { url = "https://files.pythonhosted.org/packages/2b/77/c13afad1a06824c1c942afd0205e78ff17f0ee06fc1a943f6e2135cf4112/cuda_tile-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:efcb93c25563fe23d6aa083c22893fd703122eaf684b0d36874982d28a6dad0b", size = 240925, upload-time = "2026-04-20T15:52:21.283Z" }, ] [[package]] @@ -852,6 +1031,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/04/8a/31c58ffa8e1780c8f15492018997d5fb3548427f5fa0e6327becf26f00c6/cupy_cuda13x-14.1.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:42f85f692a589b92a86627113e1072c534cc9d9047433b4291b8bd7b49fb238a", size = 72812202, upload-time = "2026-05-23T01:11:51.015Z" }, { url = "https://files.pythonhosted.org/packages/98/41/be34e911811a0369e3e66b1b618dfccdea1f84ad6a2cc17f146ce9095e99/cupy_cuda13x-14.1.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:eef76f0647af5a9bfe3d0bac641f201deb5f15a644f4b13a2e68c0c62e6808fe", size = 69094718, upload-time = "2026-05-23T01:11:57.103Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c1/c92b4c9c2c561c1298dfad2e3dbb75e527ac1a15d567d8fb868fc277c80e/cupy_cuda13x-14.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:18338008d428bf04dcd73ab2489c6f90c39b7ff439ab2b609115b9bb0e16e0ec", size = 35171775, upload-time = "2026-05-23T01:12:00.57Z" }, ] [[package]] @@ -869,10 +1049,19 @@ version = "3.2.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3f/3b/ebd94c8b85f8e41b5015a9ed94ee3df866024d480d05cd08b774684fb81d/cython-3.2.5.tar.gz", hash = "sha256:3dd42e4cf36ad15f265bdfec2337cc00c688c8eb6d374ffd13bb19437c27bba1", size = 3286381, upload-time = "2026-05-23T19:34:08.439Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/30/f648409de61fd74ae63090071061145059664cc9b9ff8578197601a3beb6/cython-3.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5d7a60835345a8bd29d3aa57070880cc3ce017ea0ade7b9f771ce4bf539b1f", size = 2968935, upload-time = "2026-05-23T19:34:49Z" }, { url = "https://files.pythonhosted.org/packages/4f/1b/95f07b5c0f1996e8e23b30d7aaadf5ecb9fb14d730c48af0963a359fdc25/cython-3.2.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b564f67b01bffa2521f475794b49f2787709cec1f91d5935a38eba37f2b359", size = 3223037, upload-time = "2026-05-23T19:34:51.634Z" }, { url = "https://files.pythonhosted.org/packages/b7/29/ac650cf7eb449619b16d13bc452cac254f3a1843ca0d66dc462993bd4b23/cython-3.2.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0a81220817ff954eddf4512a5b82089094a2f523eb1dc4ad555efd6f07b009b4", size = 3382276, upload-time = "2026-05-23T19:34:53.858Z" }, + { url = "https://files.pythonhosted.org/packages/bb/0f/b3ce218dd833313e9d90c38bdc285f592e50e8e9bb981b49126cd2082141/cython-3.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:3795237ab49753647e329181b140c424e8aa97543074f171f8d2c45e5014a06e", size = 2757027, upload-time = "2026-05-23T19:34:55.803Z" }, + { url = "https://files.pythonhosted.org/packages/a3/de/e3e0cf5704fe569d54b8cd5dc316c9fbf08b1b74728732f86e90168b7a3f/cython-3.2.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:224149d18d980e6ea5001b70fc7ce096c1891d59035dfa9cc5ede50f55804913", size = 2879054, upload-time = "2026-05-23T19:35:18.265Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d1/0a6a8caa35c4c57a1f1866b1141c2d00c6af67f73edbe34b2baec6919ccf/cython-3.2.5-cp39-abi3-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:992a50e90d01813333752f374a4405863113059ec67102ab8d6a431a171ee328", size = 3210422, upload-time = "2026-05-23T19:35:20.641Z" }, + { url = "https://files.pythonhosted.org/packages/07/b8/2523398ec96bb0c9bf69ada625a2256a581940b09fe11fcd0029f26ef4ad/cython-3.2.5-cp39-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8d7b81e6a52a84a02993f01aa5873786ba1dd593c892d93d5fe9866da0bad297", size = 2863809, upload-time = "2026-05-23T19:35:22.416Z" }, { url = "https://files.pythonhosted.org/packages/ff/3d/6b2f316d97bdb02283d79934e50da5cedfec65a536cdd3d69cc3a93486f9/cython-3.2.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:34d21aeb08477c9173e8be7a566b19e880a7c8109ec6bb47a4b20cb680141114", size = 2992518, upload-time = "2026-05-23T19:35:24.737Z" }, + { url = "https://files.pythonhosted.org/packages/68/2c/c9238db1eba208e226d363c00c8b74bf531a6b40c75df2334baa85e142bf/cython-3.2.5-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c4c79e697db55f082a2d3ba97702e71881d5bb1f56f0a80fa338e69101e4c59b", size = 2886221, upload-time = "2026-05-23T19:35:26.64Z" }, + { url = "https://files.pythonhosted.org/packages/2d/15/229cc5c2ed92bb8b43c73a3d31c2b4eaf498409300c34a06d93147f7a42b/cython-3.2.5-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:39acb30eba78ba6d995d5cf3d97d57d450663d93aac6f8b93753d2b89d768c60", size = 3226990, upload-time = "2026-05-23T19:35:28.979Z" }, { url = "https://files.pythonhosted.org/packages/56/31/9c0024f2c772fc303f8cae2a204bcad2fedfaf921ba71cf13a878639432d/cython-3.2.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:382122de8d6b6024fc374fabc3a2b14ba5860ed981c25055ed14fe44278b9dc7", size = 3111004, upload-time = "2026-05-23T19:35:30.957Z" }, + { url = "https://files.pythonhosted.org/packages/82/71/8b528247e42ee63cbe1c1d53805d30b28663fa782c88da4a9b69a1a412dd/cython-3.2.5-cp39-abi3-win32.whl", hash = "sha256:0bc29c7f870b09efdb1f583fbec9592b33af81a7ce273b89c8f5163d7572d5c1", size = 2440395, upload-time = "2026-05-23T19:35:33.082Z" }, + { url = "https://files.pythonhosted.org/packages/50/4d/81c91d3279d156ee2c9ead7ed9eaa862e498066d759e92fb83d0d842c5a7/cython-3.2.5-cp39-abi3-win_arm64.whl", hash = "sha256:85b2944c3eddfc230f9082720195a2e9f869908e5a8b3185be1be832755ee7fc", size = 2446963, upload-time = "2026-05-23T19:35:35.267Z" }, { url = "https://files.pythonhosted.org/packages/d4/5c/9cd909e6a8bb178e4e0f9a2a9227c8201a2be38abe45ada4a4c3e9154277/cython-3.2.5-py3-none-any.whl", hash = "sha256:dc1c8cebb7df5bce37f5f8dc1e5bf04313272a5973d50a55c0ec76c83812911b", size = 1257622, upload-time = "2026-05-23T19:34:05.163Z" }, ] @@ -915,13 +1104,144 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/65/99/00f3196036501b53032c4b1ab8337a0b978dee832ed276dae3815df4e8b5/datasets-4.8.5-py3-none-any.whl", hash = "sha256:5079900781719c0e063a8efdd2cd95a31ad0c63209178669cd23cf1b926149ff", size = 528973, upload-time = "2026-04-27T15:43:53.702Z" }, ] +[[package]] +name = "daytona" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "aiohttp", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona-analytics-api-client", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona-analytics-api-client-async", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona-api-client", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona-api-client-async", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona-toolbox-api-client", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona-toolbox-api-client-async", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "deprecated", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "httpx", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "httpx-ws", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "obstore", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-api", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-exporter-otlp-proto-http", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-instrumentation-aiohttp-client", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-sdk", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dotenv", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-multipart", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-socketio", extra = ["asyncio-client", "client"], marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "toml", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "urllib3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "wsproto", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/f4/ee8ab4cebd17a3c6033c656d5a7cb00d492865d74f888dc6603b3c9c26e9/daytona-0.201.0.tar.gz", hash = "sha256:62c0e05f7ffbacbc319151111bb60ad53f8882597449c88a73c7e5d4e4e4f569", size = 182380, upload-time = "2026-07-27T08:17:17.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/5f/7d59dc8b8a6600bbfcbb588398565e0db1748320fb982f634bf70ba85fe9/daytona-0.201.0-py3-none-any.whl", hash = "sha256:4488cdf19ffdc0f1acdb5cbe6128349d64ec809e4bc12c6a6885802ca2303a90", size = 218674, upload-time = "2026-07-27T08:17:19.26Z" }, +] + +[[package]] +name = "daytona-analytics-api-client" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "urllib3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/c0/fb1facfe6be00db733d74ba20e9a94d75442d14b9f5dbf975eae03fb9fad/daytona_analytics_api_client-0.201.0.tar.gz", hash = "sha256:43490fbae09877a8dd8559c3737bfa8cf9d4c83e41c051e53c55492c40fd106c", size = 30052, upload-time = "2026-07-27T08:16:57.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/4e/3b3eee66d9046f7b847bf60b49eba530ab1d3cfd91660986365e62d7e080/daytona_analytics_api_client-0.201.0-py3-none-any.whl", hash = "sha256:57ad08ae442cbe605bd020b42ee9131a9a35a22ab515bf44dc3a661141009459", size = 45012, upload-time = "2026-07-27T08:16:57.918Z" }, +] + +[[package]] +name = "daytona-analytics-api-client-async" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "aiohttp-retry", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/68/e26ed7feade3e0038594a6ec4c15cee7909aa4cee09f58c44659a5d95f9c/daytona_analytics_api_client_async-0.201.0.tar.gz", hash = "sha256:d3abe3ede6bce850c75bb38bfe4fb19e787428d6b25d783fd83c283ce1e7ae6d", size = 30075, upload-time = "2026-07-27T08:16:48.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/1f/589a6ca887acf1ffb3916b7b633efcff0aee98d920cb94857bc581f84ebb/daytona_analytics_api_client_async-0.201.0-py3-none-any.whl", hash = "sha256:2037229523115cc80a48cb82bb862d9a220b613c1189637fd2532d3039c7af6b", size = 45283, upload-time = "2026-07-27T08:16:49.425Z" }, +] + +[[package]] +name = "daytona-api-client" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "urllib3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/61/96162514ed811fa9c187e2698e18203d532ae495f5243006844a1e274cc2/daytona_api_client-0.201.0.tar.gz", hash = "sha256:0f19bc371982b8c82680ad8ae6983c33e2cfbe59babcaea575c7ce121af81623", size = 129148, upload-time = "2026-07-27T08:17:03.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/b1/9d860a122b4e540906b79841f65d1e69532db523cc6bfff850642787fd37/daytona_api_client-0.201.0-py3-none-any.whl", hash = "sha256:5f7b835488b60f873531e4f5b299fc566b2f342161866584f35070f2d2beaf97", size = 327241, upload-time = "2026-07-27T08:17:04.863Z" }, +] + +[[package]] +name = "daytona-api-client-async" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "aiohttp-retry", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/7d/dd3afb430077ef0cbb925f4b15fe757b3ac75dd436f4b7778c2a59e1a1b0/daytona_api_client_async-0.201.0.tar.gz", hash = "sha256:d269b2e26a418f3c922654806165309dbed408d45a6780b430d4e2efec4a1987", size = 129824, upload-time = "2026-07-27T08:16:49.147Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/3b/1ad3942c305d0946753f1cc51beff29b2f19ed01c075c4d5f2caa44906e1/daytona_api_client_async-0.201.0-py3-none-any.whl", hash = "sha256:376d01d9a3ce872bce085b4d2217519cf470d660e8bc4bd9755036d67f71f2ee", size = 329912, upload-time = "2026-07-27T08:16:50.189Z" }, +] + +[[package]] +name = "daytona-toolbox-api-client" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "urllib3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/92/a3/f3e4bcaef5201fd75ef45f0fa80ca86fda54c23660fc409935ef3b96af0c/daytona_toolbox_api_client-0.201.0.tar.gz", hash = "sha256:726d7b00dbd9b233dc0d07314bb354748ac90bfedcbec102fc360119cf73a275", size = 88034, upload-time = "2026-07-27T08:16:58.304Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a6/38ac9893f93459d7a3ec80aa0de3decc96922e2b1aca6e224d11deb10094/daytona_toolbox_api_client-0.201.0-py3-none-any.whl", hash = "sha256:02fa2086941abfabb6e096f2a16460ff104064c2749535fead794c40bee0f141", size = 252389, upload-time = "2026-07-27T08:16:59.557Z" }, +] + +[[package]] +name = "daytona-toolbox-api-client-async" +version = "0.201.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "aiohttp-retry", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-dateutil", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/8d/4fe5bf1e42b2cf82077cb3ae1e4fd57a84e2b428af138538eabba9d3a8e2/daytona_toolbox_api_client_async-0.201.0.tar.gz", hash = "sha256:3fc8acec0cb301f3b041fa67f54d4544b2d23fb51a50ad39660d08d585dfeabc", size = 81939, upload-time = "2026-07-27T08:16:49.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/fc/7850319223ef4425ad069eea86946deaa4f57600fd6168ac991d38323a1b/daytona_toolbox_api_client_async-0.201.0-py3-none-any.whl", hash = "sha256:98459520781ee59d485e3418207cbdbe1220de29f5f49dd06deab18436e2797b", size = 250873, upload-time = "2026-07-27T08:16:50.892Z" }, +] + [[package]] name = "debugpy" version = "1.8.20" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/15/e2/fc500524cc6f104a9d049abc85a0a8b3f0d14c0a39b9c140511c61e5b40b/debugpy-1.8.20-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:5dff4bb27027821fdfcc9e8f87309a28988231165147c31730128b1c983e282a", size = 2539560, upload-time = "2026-01-29T23:03:48.738Z" }, { url = "https://files.pythonhosted.org/packages/90/83/fb33dcea789ed6018f8da20c5a9bc9d82adc65c0c990faed43f7c955da46/debugpy-1.8.20-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:84562982dd7cf5ebebfdea667ca20a064e096099997b175fe204e86817f64eaf", size = 4293272, upload-time = "2026-01-29T23:03:50.169Z" }, + { url = "https://files.pythonhosted.org/packages/a6/25/b1e4a01bfb824d79a6af24b99ef291e24189080c93576dfd9b1a2815cd0f/debugpy-1.8.20-cp313-cp313-win32.whl", hash = "sha256:da11dea6447b2cadbf8ce2bec59ecea87cc18d2c574980f643f2d2dfe4862393", size = 5331208, upload-time = "2026-01-29T23:03:51.547Z" }, + { url = "https://files.pythonhosted.org/packages/13/f7/a0b368ce54ffff9e9028c098bd2d28cfc5b54f9f6c186929083d4c60ba58/debugpy-1.8.20-cp313-cp313-win_amd64.whl", hash = "sha256:eb506e45943cab2efb7c6eafdd65b842f3ae779f020c82221f55aca9de135ed7", size = 5372930, upload-time = "2026-01-29T23:03:53.585Z" }, { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, ] @@ -942,8 +1262,10 @@ dependencies = [ { name = "numpy", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/fb/2d2f27f9fc88b664b3713ed44ef2b8240964903c99def4951d327daeba87/decord2-3.3.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:59e85f8436fc73743057e23b30321afb34818bb82d7c4cec7347f60fb9de2d21", size = 17311167, upload-time = "2026-04-06T18:09:51.709Z" }, { url = "https://files.pythonhosted.org/packages/e8/37/947bc17d6a16f5c678ab2c6ba3330b20f617ec7652f103051881cf1d98d9/decord2-3.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:deadd17cc00b65545ef731fb5f58e05d625dc8db5fbda25edc9bd30469343413", size = 25036754, upload-time = "2026-04-06T18:09:54.204Z" }, { url = "https://files.pythonhosted.org/packages/61/ab/ff85679c25708844a5e1f30e8243dfdb40985b9ce04496dde84a698f4eee/decord2-3.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e8d5408963552843411f2d74aac8025d0bb99c975c48b80e36c989297cf2d145", size = 27392918, upload-time = "2026-04-06T18:09:57.154Z" }, + { url = "https://files.pythonhosted.org/packages/d3/b7/4bc9512474269eda8527d358040ab8a608fe001ab8147c8b238ad4841cc4/decord2-3.3.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:c633a703be369a8bb919f7586f5a39398a7ed7019a8f8ae3931fdff2b87d6a2f", size = 17311166, upload-time = "2026-04-06T18:10:00.088Z" }, { url = "https://files.pythonhosted.org/packages/fe/28/7d116e141a4ec1a3a7ba3ddb7f5e5e7811a23de5468818501ec640a2995b/decord2-3.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:6c7e50d5e3b3471672641cb296bb2616348638e9ce22ecd17bfadc0897907baf", size = 25036756, upload-time = "2026-04-06T18:10:02.647Z" }, { url = "https://files.pythonhosted.org/packages/5e/4c/5cb20dcbb7b62d9453b8d1b18a62f02f8005b402747bbc1d7408bf5a57ce/decord2-3.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3d87266f9a4d211a03e2ce23d64a92e84edbc4364bf36356db47031f9f2ce45e", size = 27392917, upload-time = "2026-04-06T18:10:05.232Z" }, ] @@ -993,6 +1315,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] +[[package]] +name = "deprecated" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, +] + [[package]] name = "depyf" version = "0.20.0" @@ -1131,8 +1465,14 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/4c/3d/7ea85d70d85f7d5ed5bf28dc742f106d8334e84286fbc852d983273dd890/dulwich-1.2.6.tar.gz", hash = "sha256:405cfd53a99374ff03aacdd7a86d6a07615feca072ed69721f49ae2ebaa3eab4", size = 1257895, upload-time = "2026-05-31T14:32:52.758Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/ea/f0d0aaf7c9e36f5490579a20ed37c85afd19e90177c2e270ff533d7fd533/dulwich-1.2.6-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:cdd15b8442b527575d733d90cfd6d3c4cbaebf989e2298b0cb57a7916c66254f", size = 1532486, upload-time = "2026-05-31T14:32:18.668Z" }, + { url = "https://files.pythonhosted.org/packages/14/4e/5c212c2dcc2d8c06cafdcdc7893d9516cb861ec277f25a0f058f98512d22/dulwich-1.2.6-cp313-cp313-android_21_x86_64.whl", hash = "sha256:dd2783352917b7cb3ab12b7c3f7757210d93af6df0bd2d876a8e5b53b2feb3eb", size = 1525768, upload-time = "2026-05-31T14:32:20.174Z" }, + { url = "https://files.pythonhosted.org/packages/f4/84/7ff849d4fe769cb6439fc50322381b7eb3d6e5d64da9e5d8337c985a7748/dulwich-1.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:204d14692fb1dd850ab773690f7530f4065f405e9e7dd3f85bdf92e9330ffa2d", size = 1396354, upload-time = "2026-05-31T14:32:21.52Z" }, + { url = "https://files.pythonhosted.org/packages/29/4d/2cb9662dd57417a11e5828f2b8f7607cfaccb42dcd9b6d69316755a5f5e0/dulwich-1.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:21e2e9b81ab04ad83f2d4101ac515ef56ee08d06fd853c1a7ac255f20bb49963", size = 1335031, upload-time = "2026-05-31T14:32:22.978Z" }, { url = "https://files.pythonhosted.org/packages/2e/82/38ccfa7ee30c13d44734c5b1eb92ad0c95a96035319040e2c0b2011eee75/dulwich-1.2.6-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7b4a2f497718bfe1a3b21f933ee27c111b9cea560c0b2d8a6d939e1b5f297f79", size = 1417366, upload-time = "2026-05-31T14:32:24.295Z" }, { url = "https://files.pythonhosted.org/packages/be/a1/239d52cbd94482c064821a0ccece888aac105a81f3f9719b9622c52fe6ec/dulwich-1.2.6-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5ff9f36c95deaf7eb5d6ccde4c68adbcb932a87e03c1b479a8d94d779e7cc5d2", size = 1442588, upload-time = "2026-05-31T14:32:25.731Z" }, + { url = "https://files.pythonhosted.org/packages/6e/92/739dc9e4d5da0b1c09b752f8aad94a518ff5eca7db2f5039ba7d5976b81f/dulwich-1.2.6-cp313-cp313-win32.whl", hash = "sha256:04252b107a1600325f5f0301dde8b5b62f5bb51a0467e360070baddbb4edcea7", size = 1018371, upload-time = "2026-05-31T14:32:27.147Z" }, + { url = "https://files.pythonhosted.org/packages/bb/28/626dc722ab20e0e5d0bf67e212494563f514790bc9c4b7c0133fdf491a5d/dulwich-1.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:6fd9911fb57ee2d6eefaf895df65e1139fbc911fa560e959b38feabe5f15003f", size = 1032986, upload-time = "2026-05-31T14:32:28.66Z" }, { url = "https://files.pythonhosted.org/packages/24/15/61bd455d33979584f19d3a6e0b49b49e0d891bc680fc8cc7b028aea7360d/dulwich-1.2.6-py3-none-any.whl", hash = "sha256:8d8175dbe4feaf62bcafc8708448bfe223b4dfc71609be25c0cf2b0962abc36c", size = 688260, upload-time = "2026-05-31T14:32:51.285Z" }, ] @@ -1225,8 +1565,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "pydantic", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "starlette", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "typing-inspection", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] @@ -1293,10 +1632,22 @@ version = "0.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/03/0f/0aeb3fc50046617702acc0078b277b58367fd62eb727b9ec733ae0e8bbcc/fastar-0.11.0.tar.gz", hash = "sha256:aa7f100f7313c03fdb20f1385927ba95671071ba308ad0c1763fef295e1895ce", size = 70238, upload-time = "2026-04-13T17:11:17.143Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/d6/3be260037e86fb694e88d47f583bac3a0188c99cee1a6b257ac26cb6b53c/fastar-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:33f544b08b4541b678e53749b4552a44720d96761fb79c172b005b1089c443ed", size = 707975, upload-time = "2026-04-13T17:09:58.866Z" }, + { url = "https://files.pythonhosted.org/packages/e1/cd/7867aefb1784662554a335f2952c75a50f0c70585ed0d2210d6cc15e5627/fastar-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c1c792447e4a642745f347ff9847c52af39633071c57ee67ed53c157fc3506", size = 628460, upload-time = "2026-04-13T17:09:43.776Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2b/d11d84bdd5e0e377771b955755771e3460b290da5809cb78c1b735ee2228/fastar-0.11.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:881247e6b6eaea59fc6569f9b61447aa6b9fc2ee864e048b4643d69c52745805", size = 863054, upload-time = "2026-04-13T17:09:13.048Z" }, { url = "https://files.pythonhosted.org/packages/25/39/d3f428b318fa940b1b6e785b8d54fc895dfb5d5b945ef8d5442ffa904fb2/fastar-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:863b7929845c9fec92ef6c8d59579cf46af5136655e5342f8df5cebe46cab06c", size = 760247, upload-time = "2026-04-13T17:07:57.396Z" }, + { url = "https://files.pythonhosted.org/packages/9e/04/03949aee82aabb8ede06ac5a4a5579ffaf98a8fe59ce958494508ff15513/fastar-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96b4a57df12bf3211662627a3ea29d62ecb314a2434a0d0843f9fc23e47536e5", size = 756512, upload-time = "2026-04-13T17:08:12.415Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0c/2ca1ae0a3828ca51047962d932b80daca2522db73e8cb9d040cb6ebe28d5/fastar-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceef1c2c4df7b7b8ebd3f5d718bbf457b9bbdf25ce0bd07870211ec4fbd9aff4", size = 922183, upload-time = "2026-04-13T17:08:27.187Z" }, + { url = "https://files.pythonhosted.org/packages/65/68/7fe808b1f73a68e686f25434f538c6dc10ef4dfb3db0ace22cd861744bf8/fastar-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8e545918441910a779659d4759ad0eef349e935fbdb4668a666d3681567eb05", size = 816394, upload-time = "2026-04-13T17:08:57.657Z" }, { url = "https://files.pythonhosted.org/packages/1f/17/07d086080f8a83b8d7966955e29bcdbd6a060f5bd949dc9d5abd3658cead/fastar-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28095bb8f821e85fc2764e1a55f03e5e2876dee2abe7cd0ee9420d929905d643", size = 818983, upload-time = "2026-04-13T17:09:28.46Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e2/2c4edf0910af2e814ff6d65b77a91196d472ca8a9fb2033bd983f6856caa/fastar-0.11.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0fafb95ecbe70f666a5e9b35dd63974ccdc9bb3d99ccdbd4014a823ec3e659b5", size = 884689, upload-time = "2026-04-13T17:08:42.763Z" }, { url = "https://files.pythonhosted.org/packages/fa/ba/04fdcbd6558e60de4ced3b55230fac47675d181252582b2fcec3c74608e5/fastar-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af48fed039b94016629dcdad1c95c90c486326dd068de2b0a4df419ee09b6821", size = 970677, upload-time = "2026-04-13T17:10:15.124Z" }, + { url = "https://files.pythonhosted.org/packages/df/b3/2b860a9658550167dbd5824c85e88d0b4b912bf493e42a6322544d6e483d/fastar-0.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:74cd96163f39b8638ab4e8d49708ca887959672a22871d8170d01f067319533b", size = 1034026, upload-time = "2026-04-13T17:10:32.318Z" }, + { url = "https://files.pythonhosted.org/packages/b7/9b/fa42ea1188b144bac4b1b60753dfd449974a4d5eda132029ee7711569f94/fastar-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e8b993cb5613bab495ed482810bedc0986633fcb9a3b55c37ec88e0d6714f6a", size = 1071147, upload-time = "2026-04-13T17:10:48.833Z" }, { url = "https://files.pythonhosted.org/packages/95/c8/d2e501556dca9f1fbc9246111a31792fb49ad908fa4927f34938a97a3604/fastar-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfe39d91fc28e37e06162d94afe01050220edb7df554acb5b702b5503e564816", size = 1028377, upload-time = "2026-04-13T17:11:06.374Z" }, + { url = "https://files.pythonhosted.org/packages/db/33/5f11f23eca0a569cd052507bc45dda2e5468697f8665728d25be44120f7d/fastar-0.11.0-cp313-cp313-win32.whl", hash = "sha256:c5f63d4d99ff4bfb37c659982ec413358bdee747005348756cc50a04d412d989", size = 454089, upload-time = "2026-04-13T17:11:46.821Z" }, + { url = "https://files.pythonhosted.org/packages/da/2f/35ff03c939cba7a255a9132367873fec6c355fd06a7f84fedcbaf4c8129f/fastar-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8690ed1928d31ded3ada308e1086525fb3871f5fa81e1b69601a3f7774004583", size = 486312, upload-time = "2026-04-13T17:11:32.86Z" }, + { url = "https://files.pythonhosted.org/packages/ef/71/ee9246cbfcbfd4144558f35e7e9a306ffe0a7564730a5188c45f21d2dab8/fastar-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:d977ded9d98a0719a305e0a4d5ee811f1d3e856d853a50acb8ae833c3cd6d5d2", size = 461975, upload-time = "2026-04-13T17:11:22.589Z" }, ] [[package]] @@ -1577,10 +1928,14 @@ version = "4.63.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" }, + { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" }, { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" }, { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" }, { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" }, { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" }, + { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" }, { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, ] @@ -1590,14 +1945,38 @@ 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/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" }, ] @@ -1767,10 +2146,16 @@ version = "3.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3c/3f/dbf99fb14bfeb88c28f16729215478c0e265cacd6dc22270c8f31bb6892f/greenlet-3.5.0.tar.gz", hash = "sha256:d419647372241bc68e957bf38d5c1f98852155e4146bd1e4121adea81f4f01e4", size = 196995, upload-time = "2026-04-27T13:37:15.544Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/58/fc576f99037ce19c5aa16628e4c3226b6d1419f72a62c79f5f40576e6eb3/greenlet-3.5.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5a5ed18de6a0f6cc7087f1563f6bd93fc7df1c19165ca01e9bde5a5dc281d106", size = 285066, upload-time = "2026-04-27T12:23:05.033Z" }, { url = "https://files.pythonhosted.org/packages/4a/ba/b28ddbe6bfad6a8ac196ef0e8cff37bc65b79735995b9e410923fffeeb70/greenlet-3.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a717fbc46d8a354fa675f7c1e813485b6ba3885f9bef0cd56e5ba27d758ff5b", size = 604414, upload-time = "2026-04-27T12:52:42.358Z" }, + { url = "https://files.pythonhosted.org/packages/09/06/4b69f8f0b67603a8be2790e55107a190b376f2627fe0eaf5695d85ffb3cd/greenlet-3.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ddc090c5c1792b10246a78e8c2163ebbe04cf877f9d785c230a7b27b39ad038e", size = 617349, upload-time = "2026-04-27T12:59:43.32Z" }, + { url = "https://files.pythonhosted.org/packages/6a/15/a643b4ecd09969e30b8a150d5919960caae0abe4f5af75ab040b1ab85e78/greenlet-3.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4964101b8585c144cbda5532b1aa644255126c08a265dae90c16e7a0e63aaa9d", size = 623234, upload-time = "2026-04-27T13:02:40.611Z" }, { url = "https://files.pythonhosted.org/packages/8a/17/a3918541fd0ddefe024a69de6d16aa7b46d36ac19562adaa63c7fa180eff/greenlet-3.5.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2094acd54b272cb6eae8c03dd87b3fa1820a4cef18d6889c378d503500a1dc13", size = 613927, upload-time = "2026-04-27T12:25:30.28Z" }, + { url = "https://files.pythonhosted.org/packages/77/18/3b13d5ef1275b0ffaf933b05efa21408ac4ca95823c7411d79682e4fdcff/greenlet-3.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:7022615368890680e67b9965d33f5773aade330d5343bbe25560135aaa849eae", size = 425243, upload-time = "2026-04-27T13:05:15.689Z" }, { url = "https://files.pythonhosted.org/packages/ee/e1/bd0af6213c7dd33175d8a462d4c1fe1175124ebed4855bc1475a5b5242c2/greenlet-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5e05ba267789ea87b5a155cf0e810b1ab88bf18e9e8740813945ceb8ee4350ba", size = 1570893, upload-time = "2026-04-27T12:53:29.483Z" }, { url = "https://files.pythonhosted.org/packages/9b/2a/0789702f864f5382cb476b93d7a9c823c10472658102ccd65f415747d2e2/greenlet-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0ecec963079cd58cbd14723582384f11f166fd58883c15dcbfb342e0bc9b5846", size = 1636060, upload-time = "2026-04-27T12:25:28.845Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8f/22bf9df92bbff0eb07842b60f7e63bf7675a9742df628437a9f02d09137f/greenlet-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:728d9667d8f2f586644b748dbd9bb67e50d6a9381767d1357714ea6825bb3bf5", size = 238740, upload-time = "2026-04-27T12:24:01.341Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b7/9c5c3d653bd4ff614277c049ac676422e2c557db47b4fe43e6313fc005dc/greenlet-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:47422135b1d308c14b2c6e758beedb1acd33bb91679f5670edf77bf46244722b", size = 235525, upload-time = "2026-04-27T12:23:12.308Z" }, ] [[package]] @@ -1782,10 +2167,16 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" }, + { url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" }, { url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" }, + { url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" }, { url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" }, { url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" }, + { url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" }, { url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" }, ] [[package]] @@ -1825,10 +2216,16 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/94/c8/1223f29c84a143ae9a56c084fc96894de0ba84b6e8d60a26241abd81d278/grpcio_tools-1.80.0.tar.gz", hash = "sha256:26052b19c6ce0dcf52d1024496aea3e2bdfa864159f06dc7b97b22d041a94b26", size = 6133212, upload-time = "2026-03-30T08:52:39.077Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/44/d9/f7887a4805939e9a85d03744b66fc02575dc1df3c3e8b4d9ec000ee7a33d/grpcio_tools-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e7046837859bbfd10b01786056145480155c16b222c9e209215b68d3be13060e", size = 2550319, upload-time = "2026-03-30T08:51:19.117Z" }, + { url = "https://files.pythonhosted.org/packages/57/5a/c8a05b32bd7203f1b9f4c0151090a2d6179d6c97692d32f2066dc29c67a6/grpcio_tools-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a447f28958a8fe84ff0d9d3d9473868feb27ee4a9c9c805e66f5b670121cec59", size = 5709681, upload-time = "2026-03-30T08:51:21.991Z" }, { url = "https://files.pythonhosted.org/packages/82/6b/794350ed645c12c310008f97068f6a6fd927150b0d0d08aad1d909e880b1/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:75f00450e08fe648ad8a1eeb25bc52219679d54cdd02f04dfdddc747309d83f6", size = 2596820, upload-time = "2026-03-30T08:51:24.323Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b2/b39e7b79f7c878135e0784a53cd7260ee77260c8c7f2c9e46bca8e05d017/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3db830eaff1f2c2797328f2fa86c9dcdbd7d81af573a68db81e27afa2182a611", size = 2909193, upload-time = "2026-03-30T08:51:27.025Z" }, { url = "https://files.pythonhosted.org/packages/10/f3/abe089b058f87f9910c9a458409505cbeb0b3e1c2d993a79721d02ee6a32/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7982b5fe42f012686b667dda12916884de95c4b1c65ff64371fb7232a1474b23", size = 2660197, upload-time = "2026-03-30T08:51:29.392Z" }, { url = "https://files.pythonhosted.org/packages/09/c3/3f7806ad8b731d8a89fe3c6ed496473abd1ef4c9c42c9e9a8836ce96e377/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6451b3f4eb52d12c7f32d04bf8e0185f80521f3f088ad04b8d222b3a4819c71e", size = 3113144, upload-time = "2026-03-30T08:51:31.671Z" }, + { url = "https://files.pythonhosted.org/packages/fe/f5/415ef205e0b7e75d2a2005df6120145c4f02fda28d7b3715b55d924fe1a4/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:258bc30654a9a2236be4ca8e2ad443e2ac6db7c8cc20454d34cce60265922726", size = 3661897, upload-time = "2026-03-30T08:51:34.849Z" }, { url = "https://files.pythonhosted.org/packages/e3/d3/2ad54764c2a9547080dd8518f4a4dc7899c7e6e747a1b1de542ce6a12066/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:865a2b8e6334c838976ab02a322cbd55c863d2eaf3c1e1a0255883c63996772a", size = 3328786, upload-time = "2026-03-30T08:51:37.265Z" }, + { url = "https://files.pythonhosted.org/packages/eb/63/23ab7db01f9630ab4f3742a2fc9fbff38b0cfc30c976114f913950664a75/grpcio_tools-1.80.0-cp313-cp313-win32.whl", hash = "sha256:f760ac1722f33e774814c37b6aa0444143f612e85088ead7447a0e9cd306a1f1", size = 997087, upload-time = "2026-03-30T08:51:39.137Z" }, + { url = "https://files.pythonhosted.org/packages/9b/af/b1c1c4423fb49cb7c8e9d2c02196b038c44160b7028b425466743c6c81fa/grpcio_tools-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:7843b9ac6ff8ca508424d0dd968bd9a1a4559967e4a290f26be5bd6f04af2234", size = 1162167, upload-time = "2026-03-30T08:51:41.498Z" }, ] [[package]] @@ -1886,14 +2283,22 @@ version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/74/d8/5c06fc76461418326a7decf8367480c35be11a41fd938633929c60a9ec6b/hf_xet-1.5.0.tar.gz", hash = "sha256:e0fb0a34d9f406eed88233e829a67ec016bec5af19e480eac65a233ea289a948", size = 837196, upload-time = "2026-05-06T06:18:15.583Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/68/9b/6912c99070915a4f28119e3c5b52a9abd1eec0ad5cb293b8c967a0c6f5a2/hf_xet-1.5.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:7d70fe2ce97b9db73b9c9b9c81fe3693640aec83416a966c446afea54acfae3c", size = 4023383, upload-time = "2026-05-06T06:17:53.947Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6d/9563cfde59b5d8128a9c7ec972a087f4c782e4f7bac5a85234edfd5d5e49/hf_xet-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:73a0dae8c71de3b0633a45c73f4a4a5ed09e94b43441d82981a781d4f12baa42", size = 3792751, upload-time = "2026-05-06T06:17:51.791Z" }, { url = "https://files.pythonhosted.org/packages/07/a5/ed5a0cf35b49a0571af5a8f53416dad1877a718c021c9937c3a53cb45781/hf_xet-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a60290ec57e9b71767fba7c3645ddafdd0759974b540441510c629c6db6db24a", size = 4456058, upload-time = "2026-05-06T06:17:40.735Z" }, { url = "https://files.pythonhosted.org/packages/60/fb/3ae8bf2a7a37a4197d0195d7247fd25b3952e15cb8a599e285dfaa6f52b3/hf_xet-1.5.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e5de0f6deada0dada870bb376a11bcd1f08abf3a968a6d118f33e72d1b1eb480", size = 4250783, upload-time = "2026-05-06T06:17:38.412Z" }, { url = "https://files.pythonhosted.org/packages/a2/9b/8bae40d4d91525085137196e84eb0ed49cf65b5e96e5c3ecdadd8bd0fac2/hf_xet-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c799d49f1a5544a0ef7591c0ee75e0d6b93d6f56dc7a4979f59f7518d2872216", size = 4445594, upload-time = "2026-05-06T06:18:04.219Z" }, { url = "https://files.pythonhosted.org/packages/13/59/c74efbbd4e8728172b2cc72a2bc014d2947a4b7bdced932fbd3f5da1a4e5/hf_xet-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2baea1b0b989e5c152fe81425f7745ddc8901280ba3d97c98d8cdece7b706c60", size = 4663995, upload-time = "2026-05-06T06:18:06.1Z" }, + { url = "https://files.pythonhosted.org/packages/73/32/8e1e0410af64cda9b139d1dcebdc993a8ff9c8c7c0e2696ae356d75ccc0d/hf_xet-1.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:526345b3ed45f374f6317349df489167606736c876241ba984105afe7fd4839d", size = 3966608, upload-time = "2026-05-06T06:18:19.74Z" }, + { url = "https://files.pythonhosted.org/packages/fc/34/a8febc8f4edbea8b3e21b02ebc8b628679b84ba7e45cde624a7736b51500/hf_xet-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:786d28e2eb8315d5035544b9d137b4a842d600c434bb91bf7d0d953cce906ad4", size = 3796946, upload-time = "2026-05-06T06:18:17.568Z" }, + { url = "https://files.pythonhosted.org/packages/3d/fb/69ff198a82cae7eb1a69fb84d93b3a3e4816564d76817fe541ddc96874eb/hf_xet-1.5.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dad0dc84e941b8ba3c860659fe1fdc35c049d47cce293f003287757e971a8f56", size = 4030814, upload-time = "2026-05-06T06:17:57.933Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ff/edcc2b40162bef3ff78e14ab637e5f3b89243d6aee72f5949d3bb6a5af83/hf_xet-1.5.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:fd6e5a9b0fdac4ed03ed45ef79254a655b1aaab514a02202617fbf643f5fdf7a", size = 3798444, upload-time = "2026-05-06T06:17:55.79Z" }, { url = "https://files.pythonhosted.org/packages/49/4d/103f76b04310e5e57656696cc184690d20c466af0bca3ca88f8c8ea5d4f3/hf_xet-1.5.0-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3531b1823a0e6d77d80f9ed15ca0e00f0d115094f8ac033d5cae88f4564cc949", size = 4465986, upload-time = "2026-05-06T06:17:44.886Z" }, { url = "https://files.pythonhosted.org/packages/c4/a2/546f47f464737b3edbab6f8ddb57f2599b93d2cbb66f06abb475ccb48651/hf_xet-1.5.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9a0ee58cd18d5ea799f7ed11290bbccbe56bdd8b1d97ca74b9cc49a3945d7a3b", size = 4259865, upload-time = "2026-05-06T06:17:42.639Z" }, { url = "https://files.pythonhosted.org/packages/95/7f/1be593c1f28613be2e196473481cd81bfc5910795e30a34e8f744f6cac4f/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e60df5a42e9bed8628b6416af2cba4cba57ae9f02de226a06b020d98e1aab18", size = 4459835, upload-time = "2026-05-06T06:18:08.026Z" }, { url = "https://files.pythonhosted.org/packages/aa/b2/703569fc881f3284487e68cda7b42179978480da3c438042a6bbbb4a671c/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4b35549ce62601b84da4ff9b24d970032ace3d4430f52d91bcbb26c901d6c690", size = 4672414, upload-time = "2026-05-06T06:18:09.864Z" }, + { url = "https://files.pythonhosted.org/packages/af/37/1b6def445c567286b50aa3b33828158e135b1be44938dde59f11382a500c/hf_xet-1.5.0-cp37-abi3-win_amd64.whl", hash = "sha256:2806c7c17b4d23f8d88f7c4814f838c3b6150773fe339c20af23e1cfaf2797e4", size = 3977238, upload-time = "2026-05-06T06:18:23.621Z" }, + { url = "https://files.pythonhosted.org/packages/62/94/3b66b148778ee100dcfd69c2ca22b57b41b44d3063ceec934f209e9184ce/hf_xet-1.5.0-cp37-abi3-win_arm64.whl", hash = "sha256:b6c9df403040248c76d808d3e047d64db2d923bae593eb244c41e425cf6cd7be", size = 3806916, upload-time = "2026-05-06T06:18:21.7Z" }, ] [[package]] @@ -1924,10 +2329,13 @@ 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/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]] @@ -1954,6 +2362,21 @@ 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 = "httpx-ws" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "httpcore", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "httpx", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "wsproto", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/cd/ca91a07ae446451f7476bf3fcc909e98cb942ff032ebfda0e3fe449aca7b/httpx_ws-0.9.0.tar.gz", hash = "sha256:797373326f70eec1ae96f6e43ae9f12002fd7d73aee139a4985eaab964338a08", size = 107105, upload-time = "2026-03-28T14:11:10.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/f8/a6bc80313a9e93c888fa10534dfce2ad76ff86911b6f485777ce6de6a073/httpx_ws-0.9.0-py3-none-any.whl", hash = "sha256:71640d2fb1bf9a225775015b33cd755cfd4c5f7e21c885192fe3adc4c387b248", size = 15759, upload-time = "2026-03-28T14:11:11.887Z" }, +] + [[package]] name = "huey" version = "2.6.0" @@ -2045,14 +2468,28 @@ version = "3.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f4/57/60d1a6a512f2f0508d0bc8b4f1cc5616fd3196619b66bd6a01f9155a1292/ijson-3.5.0.tar.gz", hash = "sha256:94688760720e3f5212731b3cb8d30267f9a045fb38fb3870254e7b9504246f31", size = 68658, upload-time = "2026-02-24T03:58:30.974Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/71/d67e764a712c3590627480643a3b51efcc3afa4ef3cb54ee4c989073c97e/ijson-3.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e9cedc10e40dd6023c351ed8bfc7dcfce58204f15c321c3c1546b9c7b12562a4", size = 88544, upload-time = "2026-02-24T03:57:21.293Z" }, + { url = "https://files.pythonhosted.org/packages/1a/39/f1c299371686153fa3cf5c0736b96247a87a1bee1b7145e6d21f359c505a/ijson-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3647649f782ee06c97490b43680371186651f3f69bebe64c6083ee7615d185e5", size = 60495, upload-time = "2026-02-24T03:57:22.501Z" }, + { url = "https://files.pythonhosted.org/packages/16/94/b1438e204d75e01541bebe3e668fe3e68612d210e9931ae1611062dd0a56/ijson-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90e74be1dce05fce73451c62d1118671f78f47c9f6be3991c82b91063bf01fc9", size = 60325, upload-time = "2026-02-24T03:57:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/30/e2/4aa9c116fa86cc8b0f574f3c3a47409edc1cd4face05d0e589a5a176b05d/ijson-3.5.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:78e9ad73e7be2dd80627504bd5cbf512348c55ce2c06e362ed7683b5220e8568", size = 138774, upload-time = "2026-02-24T03:57:24.683Z" }, { url = "https://files.pythonhosted.org/packages/d2/d2/738b88752a70c3be1505faa4dcd7110668c2712e582a6a36488ed1e295d4/ijson-3.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9577449313cc94be89a4fe4b3e716c65f09cc19636d5a6b2861c4e80dddebd58", size = 149820, upload-time = "2026-02-24T03:57:26.062Z" }, { url = "https://files.pythonhosted.org/packages/ed/df/0b3ab9f393ca8f72ea03bc896ba9fdc987e90ae08cdb51c32a4ee0c14d5e/ijson-3.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e4c1178fb50aff5f5701a30a5152ead82a14e189ce0f6102fa1b5f10b2f54ff", size = 149747, upload-time = "2026-02-24T03:57:27.308Z" }, { url = "https://files.pythonhosted.org/packages/cc/a3/b0037119f75131b78cb00acc2657b1a9d0435475f1f2c5f8f5a170b66b9c/ijson-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0eb402ab026ffb37a918d75af2b7260fe6cfbce13232cc83728a714dd30bd81d", size = 151027, upload-time = "2026-02-24T03:57:28.522Z" }, + { url = "https://files.pythonhosted.org/packages/22/a0/cb344de1862bf09d8f769c9d25c944078c87dd59a1b496feec5ad96309a4/ijson-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5b08ee08355f9f729612a8eb9bf69cc14f9310c3b2a487c6f1c3c65d85216ec4", size = 142996, upload-time = "2026-02-24T03:57:29.774Z" }, { url = "https://files.pythonhosted.org/packages/ca/32/a8ffd67182e02ea61f70f62daf43ded4fa8a830a2520a851d2782460aba8/ijson-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bda62b6d48442903e7bf56152108afb7f0f1293c2b9bef2f2c369defea76ab18", size = 152068, upload-time = "2026-02-24T03:57:30.969Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d1/3578df8e75d446aab0ae92e27f641341f586b85e1988536adebc65300cb4/ijson-3.5.0-cp313-cp313-win32.whl", hash = "sha256:8d073d9b13574cfa11083cc7267c238b7a6ed563c2661e79192da4a25f09c82c", size = 53065, upload-time = "2026-02-24T03:57:31.93Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a2/f7cdaf5896710da3e69e982e44f015a83d168aa0f3a89b6f074b5426779d/ijson-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:2419f9e32e0968a876b04d8f26aeac042abd16f582810b576936bbc4c6015069", size = 55499, upload-time = "2026-02-24T03:57:32.773Z" }, + { url = "https://files.pythonhosted.org/packages/42/65/13e2492d17e19a2084523e18716dc2809159f2287fd2700c735f311e76c4/ijson-3.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4d4b0cd676b8c842f7648c1a783448fac5cd3b98289abd83711b3e275e143524", size = 93019, upload-time = "2026-02-24T03:57:33.976Z" }, + { url = "https://files.pythonhosted.org/packages/33/92/483fc97ece0c3f1cecabf48f6a7a36e89d19369eec462faaeaa34c788992/ijson-3.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:252dec3680a48bb82d475e36b4ae1b3a9d7eb690b951bb98a76c5fe519e30188", size = 62714, upload-time = "2026-02-24T03:57:34.819Z" }, + { url = "https://files.pythonhosted.org/packages/4b/88/793fe020a0fe9d9eed4c285cf4a5cfdb0a935708b3bde0d72f35c794b513/ijson-3.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:aa1b5dca97d323931fde2501172337384c958914d81a9dac7f00f0d4bfc76bc7", size = 62460, upload-time = "2026-02-24T03:57:35.874Z" }, + { url = "https://files.pythonhosted.org/packages/51/69/f1a2690aa8d4df1f4e262b385e65a933ffdc250b091531bac9a449c19e16/ijson-3.5.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7a5ec7fd86d606094bba6f6f8f87494897102fa4584ef653f3005c51a784c320", size = 199273, upload-time = "2026-02-24T03:57:37.07Z" }, { url = "https://files.pythonhosted.org/packages/ea/a2/f1346d5299e79b988ab472dc773d5381ec2d57c23cb2f1af3ede4a810e62/ijson-3.5.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:009f41443e1521847701c6d87fa3923c0b1961be3c7e7de90947c8cb92ea7c44", size = 216884, upload-time = "2026-02-24T03:57:38.346Z" }, { url = "https://files.pythonhosted.org/packages/28/3c/8b637e869be87799e6c2c3c275a30a546f086b1aed77e2b7f11512168c5a/ijson-3.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e4c3651d1f9fe2839a93fdf8fd1d5ca3a54975349894249f3b1b572bcc4bd577", size = 207306, upload-time = "2026-02-24T03:57:39.718Z" }, { url = "https://files.pythonhosted.org/packages/7f/7c/18b1c1df6951ca056782d7580ec40cea4ff9a27a0947d92640d1cc8c4ae3/ijson-3.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:945b7abcfcfeae2cde17d8d900870f03536494245dda7ad4f8d056faa303256c", size = 211364, upload-time = "2026-02-24T03:57:40.953Z" }, + { url = "https://files.pythonhosted.org/packages/f3/55/e795812e82851574a9dba8a53fde045378f531ef14110c6fb55dbd23b443/ijson-3.5.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0574b0a841ff97495c13e9d7260fbf3d85358b061f540c52a123db9dbbaa2ed6", size = 200608, upload-time = "2026-02-24T03:57:42.272Z" }, { url = "https://files.pythonhosted.org/packages/5c/cd/013c85b4749b57a4cb4c2670014d1b32b8db4ab1a7be92ea7aeb5d7fe7b5/ijson-3.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f969ffb2b89c5cdf686652d7fb66252bc72126fa54d416317411497276056a18", size = 205127, upload-time = "2026-02-24T03:57:43.286Z" }, + { url = "https://files.pythonhosted.org/packages/0e/7c/faf643733e3ab677f180018f6a855c4ef70b7c46540987424c563c959e42/ijson-3.5.0-cp313-cp313t-win32.whl", hash = "sha256:59d3f9f46deed1332ad669518b8099920512a78bda64c1f021fcd2aff2b36693", size = 55282, upload-time = "2026-02-24T03:57:44.353Z" }, + { url = "https://files.pythonhosted.org/packages/69/22/94ddb47c24b491377aca06cd8fc9202cad6ab50619842457d2beefde21ea/ijson-3.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c2839fa233746d8aad3b8cd2354e441613f5df66d721d59da4a09394bd1db2b", size = 58016, upload-time = "2026-02-24T03:57:45.237Z" }, ] [[package]] @@ -2166,12 +2603,25 @@ version = "0.14.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6e/c1/0cddc6eb17d4c53a99840953f95dd3accdc5cfc7a337b0e9b26476276be9/jiter-0.14.0.tar.gz", hash = "sha256:e8a39e66dac7153cf3f964a12aad515afa8d74938ec5cc0018adcdae5367c79e", size = 165725, upload-time = "2026-04-10T14:28:42.01Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/97/2a/09f70020898507a89279659a1afe3364d57fc1b2c89949081975d135f6f5/jiter-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:af72f204cf4d44258e5b4c1745130ac45ddab0e71a06333b01de660ab4187a94", size = 315502, upload-time = "2026-04-10T14:26:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/d6/be/080c96a45cd74f9fce5db4fd68510b88087fb37ffe2541ff73c12db92535/jiter-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4b77da71f6e819be5fbcec11a453fde5b1d0267ef6ed487e2a392fd8e14e4e3a", size = 314870, upload-time = "2026-04-10T14:26:49.149Z" }, { url = "https://files.pythonhosted.org/packages/7d/5e/2d0fee155826a968a832cc32438de5e2a193292c8721ca70d0b53e58245b/jiter-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f4ea612fe8b84b8b04e51d0e78029ecf3466348e25973f953de6e6a59aa4c1", size = 343406, upload-time = "2026-04-10T14:26:50.762Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/bf9ee0d3a4f8dc0d679fc1337f874fe60cdbf841ebbb304b374e1c9aaceb/jiter-0.14.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62fe2451f8fcc0240261e6a4df18ecbcd58327857e61e625b2393ea3b468aac9", size = 369415, upload-time = "2026-04-10T14:26:52.188Z" }, + { url = "https://files.pythonhosted.org/packages/0f/83/8e8561eadba31f4d3948a5b712fb0447ec71c3560b57a855449e7b8ddc98/jiter-0.14.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6112f26f5afc75bcb475787d29da3aa92f9d09c7858f632f4be6ffe607be82e9", size = 461456, upload-time = "2026-04-10T14:26:53.611Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c9/c5299e826a5fe6108d172b344033f61c69b1bb979dd8d9ddd4278a160971/jiter-0.14.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:215a6cb8fb7dc702aa35d475cc00ddc7f970e5c0b1417fb4b4ac5d82fa2a29db", size = 378488, upload-time = "2026-04-10T14:26:55.211Z" }, { url = "https://files.pythonhosted.org/packages/5d/37/c16d9d15c0a471b8644b1abe3c82668092a707d9bedcf076f24ff2e380cd/jiter-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ab96a30fb3cb2c7e0cd33f7616c8860da5f5674438988a54ac717caccdbaa", size = 353242, upload-time = "2026-04-10T14:26:56.705Z" }, + { url = "https://files.pythonhosted.org/packages/58/ea/8050cb0dc654e728e1bfacbc0c640772f2181af5dedd13ae70145743a439/jiter-0.14.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:3a99c1387b1f2928f799a9de899193484d66206a50e98233b6b088a7f0c1edb2", size = 356823, upload-time = "2026-04-10T14:26:58.281Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/cf71506d270e5f84d97326bf220e47aed9b95e9a4a060758fb07772170ab/jiter-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ab18d11074485438695f8d34a1b6da61db9754248f96d51341956607a8f39985", size = 392564, upload-time = "2026-04-10T14:27:00.018Z" }, { url = "https://files.pythonhosted.org/packages/b0/cc/8c6c74a3efb5bd671bfd14f51e8a73375464ca914b1551bc3b40e26ac2c9/jiter-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:801028dcfc26ac0895e4964cbc0fd62c73be9fd4a7d7b1aaf6e5790033a719b7", size = 520322, upload-time = "2026-04-10T14:27:01.664Z" }, { url = "https://files.pythonhosted.org/packages/41/24/68d7b883ec959884ddf00d019b2e0e82ba81b167e1253684fa90519ce33c/jiter-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ad425b087aafb4a1c7e1e98a279200743b9aaf30c3e0ba723aec93f061bd9bc8", size = 552619, upload-time = "2026-04-10T14:27:03.316Z" }, + { url = "https://files.pythonhosted.org/packages/b6/89/b1a0985223bbf3150ff9e8f46f98fc9360c1de94f48abe271bbe1b465682/jiter-0.14.0-cp313-cp313-win32.whl", hash = "sha256:882bcb9b334318e233950b8be366fe5f92c86b66a7e449e76975dfd6d776a01f", size = 205699, upload-time = "2026-04-10T14:27:04.662Z" }, + { url = "https://files.pythonhosted.org/packages/4c/19/3f339a5a7f14a11730e67f6be34f9d5105751d547b615ef593fa122a5ded/jiter-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:9b8c571a5dba09b98bd3462b5a53f27209a5cbbe85670391692ede71974e979f", size = 201323, upload-time = "2026-04-10T14:27:06.139Z" }, + { url = "https://files.pythonhosted.org/packages/50/56/752dd89c84be0e022a8ea3720bcfa0a8431db79a962578544812ce061739/jiter-0.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:34f19dcc35cb1abe7c369b3756babf8c7f04595c0807a848df8f26ef8298ef92", size = 191099, upload-time = "2026-04-10T14:27:07.564Z" }, + { url = "https://files.pythonhosted.org/packages/91/28/292916f354f25a1fe8cf2c918d1415c699a4a659ae00be0430e1c5d9ffea/jiter-0.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e89bcd7d426a75bb4952c696b267075790d854a07aad4c9894551a82c5b574ab", size = 320880, upload-time = "2026-04-10T14:27:09.326Z" }, { url = "https://files.pythonhosted.org/packages/ad/c7/b002a7d8b8957ac3d469bd59c18ef4b1595a5216ae0de639a287b9816023/jiter-0.14.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b25beaa0d4447ea8c7ae0c18c688905d34840d7d0b937f2f7bdd52162c98a40", size = 346563, upload-time = "2026-04-10T14:27:11.287Z" }, { url = "https://files.pythonhosted.org/packages/f9/3b/f8d07580d8706021d255a6356b8fab13ee4c869412995550ce6ed4ddf97d/jiter-0.14.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a8758dd413c51e3b7f6557cdc6921faf70b14106f45f969f091f5cda990ea", size = 357928, upload-time = "2026-04-10T14:27:12.729Z" }, + { url = "https://files.pythonhosted.org/packages/47/5b/ac1a974da29e35507230383110ffec59998b290a8732585d04e19a9eb5ba/jiter-0.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e1a7eead856a5038a8d291f1447176ab0b525c77a279a058121b5fccee257f6f", size = 203519, upload-time = "2026-04-10T14:27:14.125Z" }, + { url = "https://files.pythonhosted.org/packages/96/6d/9fc8433d667d2454271378a79747d8c76c10b51b482b454e6190e511f244/jiter-0.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e692633a12cda97e352fdcd1c4acc971b1c28707e1e33aeef782b0cbf051975", size = 190113, upload-time = "2026-04-10T14:27:16.638Z" }, ] [[package]] @@ -2248,14 +2698,35 @@ version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, + { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, + { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, + { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, + { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, + { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, + { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, + { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, + { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, + { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, + { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, ] [[package]] @@ -2286,10 +2757,19 @@ version = "0.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" }, + { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" }, { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" }, + { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" }, { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" }, { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" }, { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" }, ] [[package]] @@ -2298,8 +2778,13 @@ version = "1.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/95/48/3f7a9d3ff1b36bba92b5107a3a21286821227afe9ea464736133994d61fb/llguidance-1.3.0.tar.gz", hash = "sha256:861249afd51dc325646834462ea827e57a5c2b2042e108e6aae7059fdad9104d", size = 1070460, upload-time = "2025-10-20T19:58:44.164Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/33/be5acb85cd8cdc4afde33d9c234eece9f318e087920255af3c05864cd3e7/llguidance-1.3.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f7685222660a762e481ac633d49cc559c64980fe2ee59c8f932a5bb5cbc0c2c2", size = 3220647, upload-time = "2025-10-20T19:58:42.542Z" }, + { url = "https://files.pythonhosted.org/packages/82/e6/b48bda5b15efeaeb62bd0dba8fc6a01d4ae5457a85dbb5d18632385fe15c/llguidance-1.3.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:098030ff0687261a3f1bd54cf21fe951fc861d56d37a0671250dd36677eaf224", size = 3099830, upload-time = "2025-10-20T19:58:40.826Z" }, { url = "https://files.pythonhosted.org/packages/aa/11/44389d3d1526d7a5c38ffd587a5ebc61d7bee443ac1dea95f2089ad58f5f/llguidance-1.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f6caca5d78db7f76e1fbb0fff8607b861c32d47fa3d5dee2fc49de27ee269df", size = 2835242, upload-time = "2025-10-20T19:58:34.518Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ca/53ea256396405e4dee70d5a4a35e18543408e18bb16b251d6ca6b5d80310/llguidance-1.3.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0612bb3f034d2487b6e8f9561f02a94a6039d88273bf0c5c539a3bd3895e47d2", size = 3297480, upload-time = "2025-10-20T19:58:37.033Z" }, { url = "https://files.pythonhosted.org/packages/83/a8/1ff2bedb8f9acb46a2d2d603415d272bb622c142ea86f5b95445cc6e366c/llguidance-1.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc17e9dd602c3879bf91664a64bf72f54c74dbfbeb24ccfab6a5fe435b12f7aa", size = 3033133, upload-time = "2025-10-20T19:58:38.721Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a7/9b8086c0cfdddf3f6d47b173a404fa7ac46272f7affbee082c36740f4f1c/llguidance-1.3.0-cp39-abi3-win32.whl", hash = "sha256:2f6f558485a43e273fc5c6c974a9a3ace5d5e170076db9b40e0560e41c3ff18f", size = 2598109, upload-time = "2025-10-20T19:58:47.656Z" }, + { url = "https://files.pythonhosted.org/packages/5a/7e/809349638231f469b9056c0e1bfd924d5ef5558b3b3ec72d093b6fad33b1/llguidance-1.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:1d1cd1c8618d1a13605d3e057c978651e551c8c469b481ee4041f1d6c436002d", size = 2789946, upload-time = "2025-10-20T19:58:45.958Z" }, ] [[package]] @@ -2308,8 +2793,10 @@ version = "0.47.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz", hash = "sha256:62031ce968ec74e95092184d4b0e857e444f8fdff0b8f9213707699570c33ccc", size = 193614, upload-time = "2026-03-31T18:29:53.497Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/77/6f/4615353e016799f80fa52ccb270a843c413b22361fadda2589b2922fb9b0/llvmlite-0.47.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a3c6a735d4e1041808434f9d440faa3d78d9b4af2ee64d05a66f351883b6ceec", size = 37232771, upload-time = "2026-03-31T18:29:01.324Z" }, { url = "https://files.pythonhosted.org/packages/31/b8/69f5565f1a280d032525878a86511eebed0645818492feeb169dfb20ae8e/llvmlite-0.47.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2699a74321189e812d476a43d6d7f652f51811e7b5aad9d9bba842a1c7927acb", size = 56275178, upload-time = "2026-03-31T18:29:05.748Z" }, { url = "https://files.pythonhosted.org/packages/d6/da/b32cafcb926fb0ce2aa25553bf32cb8764af31438f40e2481df08884c947/llvmlite-0.47.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c6951e2b29930227963e53ee152441f0e14be92e9d4231852102d986c761e40", size = 55128632, upload-time = "2026-03-31T18:29:11.235Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/4898b44e4042c60fafcb1162dfb7014f6f15b1ec19bf29cfea6bf26df90d/llvmlite-0.47.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2e9adf8698d813a9a5efb2d4370caf344dbc1e145019851fee6a6f319ba760e", size = 38138695, upload-time = "2026-03-31T18:29:15.43Z" }, ] [[package]] @@ -2342,12 +2829,24 @@ version = "6.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/28/30/9abc9e34c657c33834eaf6cd02124c61bdf5944d802aa48e69be8da3585d/lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", size = 4197006, upload-time = "2026-04-18T04:32:51.613Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/08/03/69347590f1cf4a6d5a4944bb6099e6d37f334784f16062234e1f892fdb1d/lxml-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45", size = 8559689, upload-time = "2026-04-18T04:31:57.785Z" }, + { url = "https://files.pythonhosted.org/packages/3f/58/25e00bb40b185c974cfe156c110474d9a8a8390d5f7c92a4e328189bb60e/lxml-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d", size = 4617892, upload-time = "2026-04-18T04:32:01.78Z" }, { url = "https://files.pythonhosted.org/packages/f5/54/92ad98a94ac318dc4f97aaac22ff8d1b94212b2ae8af5b6e9b354bf825f7/lxml-6.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2", size = 4923489, upload-time = "2026-04-18T04:33:31.401Z" }, { url = "https://files.pythonhosted.org/packages/15/3b/a20aecfab42bdf4f9b390590d345857ad3ffd7c51988d1c89c53a0c73faf/lxml-6.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491", size = 5082162, upload-time = "2026-04-18T04:33:34.262Z" }, { url = "https://files.pythonhosted.org/packages/45/26/2cdb3d281ac1bd175603e290cbe4bad6eff127c0f8de90bafd6f8548f0fd/lxml-6.1.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc", size = 4993247, upload-time = "2026-04-18T04:33:36.674Z" }, + { url = "https://files.pythonhosted.org/packages/f6/05/d735aef963740022a08185c84821f689fc903acb3d50326e6b1e9886cc22/lxml-6.1.0-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e", size = 5613042, upload-time = "2026-04-18T04:33:39.205Z" }, { url = "https://files.pythonhosted.org/packages/ee/b8/ead7c10efff731738c72e59ed6eb5791854879fbed7ae98781a12006263a/lxml-6.1.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2", size = 5228304, upload-time = "2026-04-18T04:33:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/6b/10/e9842d2ec322ea65f0a7270aa0315a53abed06058b88ef1b027f620e7a5f/lxml-6.1.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9", size = 5341578, upload-time = "2026-04-18T04:33:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/89/54/40d9403d7c2775fa7301d3ddd3464689bfe9ba71acc17dfff777071b4fdc/lxml-6.1.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe", size = 4700209, upload-time = "2026-04-18T04:33:47.552Z" }, + { url = "https://files.pythonhosted.org/packages/85/b2/bbdcc2cf45dfc7dfffef4fd97e5c47b15919b6a365247d95d6f684ef5e82/lxml-6.1.0-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88", size = 5232365, upload-time = "2026-04-18T04:33:50.249Z" }, { url = "https://files.pythonhosted.org/packages/48/5a/b06875665e53aaba7127611a7bed3b7b9658e20b22bc2dd217a0b7ab0091/lxml-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181", size = 5043654, upload-time = "2026-04-18T04:33:52.71Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9c/e71a069d09641c1a7abeb30e693f828c7c90a41cbe3d650b2d734d876f85/lxml-6.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24", size = 4769326, upload-time = "2026-04-18T04:33:55.244Z" }, + { url = "https://files.pythonhosted.org/packages/cc/06/7a9cd84b3d4ed79adf35f874750abb697dec0b4a81a836037b36e47c091a/lxml-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e", size = 5635879, upload-time = "2026-04-18T04:33:58.509Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f0/9d57916befc1e54c451712c7ee48e9e74e80ae4d03bdce49914e0aee42cd/lxml-6.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495", size = 5224048, upload-time = "2026-04-18T04:34:00.943Z" }, { url = "https://files.pythonhosted.org/packages/99/75/90c4eefda0c08c92221fe0753db2d6699a4c628f76ff4465ec20dea84cc1/lxml-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33", size = 5250241, upload-time = "2026-04-18T04:34:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/5e/73/16596f7e4e38fa33084b9ccbccc22a15f82a290a055126f2c1541236d2ff/lxml-6.1.0-cp313-cp313-win32.whl", hash = "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62", size = 3596938, upload-time = "2026-04-18T04:31:56.206Z" }, + { url = "https://files.pythonhosted.org/packages/8e/63/981401c5680c1eb30893f00a19641ac80db5d1e7086c62cb4b13ed813038/lxml-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16", size = 3995728, upload-time = "2026-04-18T04:31:58.763Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e8/c358a38ac3e541d16a1b527e4e9cb78c0419b0506a070ace11777e5e8404/lxml-6.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d", size = 3658372, upload-time = "2026-04-18T04:32:03.629Z" }, ] [[package]] @@ -2400,14 +2899,28 @@ 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/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]] @@ -2439,12 +2952,20 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/d3/8d4f6afbecb49fc04e060a57c0fce39ea51cc163a6bd87303ccd698e4fa6/matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f", size = 8320331, upload-time = "2026-04-24T00:12:39.688Z" }, + { url = "https://files.pythonhosted.org/packages/63/d9/9e14bc7564bf92d5ffa801ae5fac819ce74b925dfb55e3ebde61a3bbad3e/matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e", size = 8216461, upload-time = "2026-04-24T00:12:42.494Z" }, { url = "https://files.pythonhosted.org/packages/8a/17/4402d0d14ccf1dfc70932600b68097fbbf9c898a4871d2cbbe79c7801a32/matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f", size = 8790091, upload-time = "2026-04-24T00:12:44.789Z" }, { url = "https://files.pythonhosted.org/packages/3e/0b/322aeec06dd9b91411f92028b37d447342770a24392aa4813e317064dad5/matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838", size = 9605027, upload-time = "2026-04-24T00:12:47.583Z" }, { url = "https://files.pythonhosted.org/packages/74/88/5f13482f55e7b00bcfc09838b093c2456e1379978d2a146844aae05350ad/matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2", size = 9671269, upload-time = "2026-04-24T00:12:50.878Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/0840fd2f93da988ec660b8ad1984abe9f25d2aed22a5e394ff1c68c88307/matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921", size = 8217588, upload-time = "2026-04-24T00:12:53.784Z" }, + { url = "https://files.pythonhosted.org/packages/47/b9/d706d06dd605c49b9f83a2aed8c13e3e5db70697d7a80b7e3d7915de6b17/matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8", size = 8136913, upload-time = "2026-04-24T00:12:56.501Z" }, + { url = "https://files.pythonhosted.org/packages/9b/45/6e32d96978264c8ca8c4b1010adb955a1a49cfaf314e212bbc8908f04a61/matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9", size = 8368019, upload-time = "2026-04-24T00:12:58.896Z" }, + { url = "https://files.pythonhosted.org/packages/86/0a/c8e3d3bba245f0f7fc424937f8ff7ef77291a36af3edb97ccd78aa93d84f/matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4", size = 8264645, upload-time = "2026-04-24T00:13:01.406Z" }, { url = "https://files.pythonhosted.org/packages/3d/aa/5bf5a14fe4fed73a4209a155606f8096ff797aad89c6c35179026571133e/matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc", size = 8802194, upload-time = "2026-04-24T00:13:03.702Z" }, { url = "https://files.pythonhosted.org/packages/dd/5e/b4be852d6bba6fd15893fadf91ff26ae49cb91aac789e95dde9d342e664f/matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99", size = 9622684, upload-time = "2026-04-24T00:13:06.647Z" }, { url = "https://files.pythonhosted.org/packages/4c/3d/ed428c971139112ef730f62770654d609467346d09d4b62617e1afd68a5a/matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d", size = 9680790, upload-time = "2026-04-24T00:13:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/e7/09/052e884aaf2b985c63cb79f715f1d5b6a3eaa7de78f6a52b9dbc077d5b53/matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8", size = 8287571, upload-time = "2026-04-24T00:13:13.087Z" }, + { url = "https://files.pythonhosted.org/packages/f4/38/ae27288e788c35a4250491422f3db7750366fc8c97d6f36fbdecfc1f5518/matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38", size = 8188292, upload-time = "2026-04-24T00:13:15.546Z" }, ] [[package]] @@ -2473,8 +2994,7 @@ dependencies = [ { name = "pyjwt", extra = ["crypto"], marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "python-multipart", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "sse-starlette", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "starlette", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "typing-inspection", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "uvicorn", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, @@ -2735,10 +3255,16 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314, upload-time = "2025-11-17T22:32:31.031Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/a1/4008f14bbc616cfb1ac5b39ea485f9c63031c4634ab3f4cf72e7541f816a/ml_dtypes-0.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c760d85a2f82e2bed75867079188c9d18dae2ee77c25a54d60e9cc79be1bc48", size = 676888, upload-time = "2025-11-17T22:31:56.907Z" }, { url = "https://files.pythonhosted.org/packages/d3/b7/dff378afc2b0d5a7d6cd9d3209b60474d9819d1189d347521e1688a60a53/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce756d3a10d0c4067172804c9cc276ba9cc0ff47af9078ad439b075d1abdc29b", size = 5036993, upload-time = "2025-11-17T22:31:58.497Z" }, { url = "https://files.pythonhosted.org/packages/eb/33/40cd74219417e78b97c47802037cf2d87b91973e18bb968a7da48a96ea44/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:533ce891ba774eabf607172254f2e7260ba5f57bdd64030c9a4fcfbd99815d0d", size = 5010956, upload-time = "2025-11-17T22:31:59.931Z" }, + { url = "https://files.pythonhosted.org/packages/e1/8b/200088c6859d8221454825959df35b5244fa9bdf263fd0249ac5fb75e281/ml_dtypes-0.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:f21c9219ef48ca5ee78402d5cc831bd58ea27ce89beda894428bc67a52da5328", size = 212224, upload-time = "2025-11-17T22:32:01.349Z" }, + { url = "https://files.pythonhosted.org/packages/8f/75/dfc3775cb36367816e678f69a7843f6f03bd4e2bcd79941e01ea960a068e/ml_dtypes-0.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:35f29491a3e478407f7047b8a4834e4640a77d2737e0b294d049746507af5175", size = 160798, upload-time = "2025-11-17T22:32:02.864Z" }, + { url = "https://files.pythonhosted.org/packages/4f/74/e9ddb35fd1dd43b1106c20ced3f53c2e8e7fc7598c15638e9f80677f81d4/ml_dtypes-0.5.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:304ad47faa395415b9ccbcc06a0350800bc50eda70f0e45326796e27c62f18b6", size = 702083, upload-time = "2025-11-17T22:32:04.08Z" }, { url = "https://files.pythonhosted.org/packages/74/f5/667060b0aed1aa63166b22897fdf16dca9eb704e6b4bbf86848d5a181aa7/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a0df4223b514d799b8a1629c65ddc351b3efa833ccf7f8ea0cf654a61d1e35d", size = 5354111, upload-time = "2025-11-17T22:32:05.546Z" }, { url = "https://files.pythonhosted.org/packages/40/49/0f8c498a28c0efa5f5c95a9e374c83ec1385ca41d0e85e7cf40e5d519a21/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531eff30e4d368cb6255bc2328d070e35836aa4f282a0fb5f3a0cd7260257298", size = 5366453, upload-time = "2025-11-17T22:32:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/8c/27/12607423d0a9c6bbbcc780ad19f1f6baa2b68b18ce4bddcdc122c4c68dc9/ml_dtypes-0.5.4-cp313-cp313t-win_amd64.whl", hash = "sha256:cb73dccfc991691c444acc8c0012bee8f2470da826a92e3a20bb333b1a7894e6", size = 225612, upload-time = "2025-11-17T22:32:08.615Z" }, + { url = "https://files.pythonhosted.org/packages/e5/80/5a5929e92c72936d5b19872c5fb8fc09327c1da67b3b68c6a13139e77e20/ml_dtypes-0.5.4-cp313-cp313t-win_arm64.whl", hash = "sha256:3bbbe120b915090d9dd1375e4684dd17a20a2491ef25d640a908281da85e73f1", size = 164145, upload-time = "2025-11-17T22:32:09.782Z" }, ] [[package]] @@ -2793,8 +3319,7 @@ dependencies = [ { name = "pyyaml", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "requests", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "sqlparse", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "starlette", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "uvicorn", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] @@ -2832,7 +3357,7 @@ dependencies = [ { name = "jmespath", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, { name = "pydantic", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, { name = "setuptools", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "starlette", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, { name = "supervisor", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/03/5a/d669bdeb5ba96db42c6ef010835a25119b05f8c35ee5f1c3f715626625fe/model_hosting_container_standards-0.1.15.tar.gz", hash = "sha256:ae8dd74d3250545c14f0a7068186c7b0f0ab6563d31e7137f556b6b660c8a6a9", size = 93994, upload-time = "2026-05-05T18:22:29.357Z" } @@ -2885,10 +3410,15 @@ 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/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]] @@ -2897,10 +3427,14 @@ version = "0.21.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e3/60/f79b9b013a16fa3a58350c9295ddc6789f2e335f36ea61ed10a21b215364/msgspec-0.21.1.tar.gz", hash = "sha256:2313508e394b0d208f8f56892ca9b2799e2561329de9763b19619595a6c0f72c", size = 319193, upload-time = "2026-04-12T21:44:50.394Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/74/f11ede02839b19ff459f88e3145df5d711626ca84da4e23520cebf819367/msgspec-0.21.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:764173717a01743f007e9f74520ed281f24672c604514f7d76c1c3a10e8edb66", size = 196176, upload-time = "2026-04-12T21:44:17.613Z" }, + { url = "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:344c7cd0eaed1fb81d7959f99100ef71ec9b536881a376f11b9a6c4803365697", size = 188524, upload-time = "2026-04-12T21:44:18.815Z" }, { url = "https://files.pythonhosted.org/packages/ca/d9/9e9d7d7e5061b47540d03d640fab9b3965ba7ae49c1b2154861c8f007518/msgspec-0.21.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48943e278b3854c2f89f955ddc6f9f430d3f0784b16e47d10604ee0463cd21f5", size = 218880, upload-time = "2026-04-12T21:44:20.028Z" }, { url = "https://files.pythonhosted.org/packages/74/66/2bb344f34abb4b57e60c7c9c761994e0417b9718ec1460bf00c296f2a7ea/msgspec-0.21.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9aa659ebb0101b1cbc31461212b87e341d961f0ab0772aaf068a99e001ec4aa", size = 225050, upload-time = "2026-04-12T21:44:21.577Z" }, { url = "https://files.pythonhosted.org/packages/1a/84/7c1e412f76092277bf760cef12b7979d03314d259ab5b5cafde5d0c1722d/msgspec-0.21.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7b27d1a8ead2b6f5b0c4f2d07b8be1ccfcc041c8a0e704781edebe3ae13c484", size = 222713, upload-time = "2026-04-12T21:44:22.83Z" }, { url = "https://files.pythonhosted.org/packages/4e/27/0bba04b2b4ef05f3d068429410bc71d2cea925f1596a8f41152cccd5edb8/msgspec-0.21.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38fe93e86b61328fe544cb7fd871fad5a27c8734bfda90f65e5dbe288ae50f61", size = 227259, upload-time = "2026-04-12T21:44:24.11Z" }, + { url = "https://files.pythonhosted.org/packages/b0/2d/09574b0eea02fed2c2c1383dbaae2c7f79dc16dcd6487a886000afb5d7c4/msgspec-0.21.1-cp313-cp313-win_amd64.whl", hash = "sha256:8bc666331c35fcce05a7cd2d6221adbe0f6058f8e750711413d22793c080ac6a", size = 189857, upload-time = "2026-04-12T21:44:25.359Z" }, + { url = "https://files.pythonhosted.org/packages/46/34/105b1576ad182879914f0c821f17ee1d13abb165cb060448f96fe2aff078/msgspec-0.21.1-cp313-cp313-win_arm64.whl", hash = "sha256:42bb1241e0750c1a4346f2aa84db26c5ffd99a4eb3a954927d9f149ff2f42898", size = 175403, upload-time = "2026-04-12T21:44:26.608Z" }, ] [[package]] @@ -2909,14 +3443,42 @@ 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/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" }, ] @@ -2949,9 +3511,13 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" }, + { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" }, { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" }, { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" }, { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" }, + { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" }, { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" }, ] @@ -3173,6 +3739,21 @@ dependencies = [ ] [package.optional-dependencies] +all = [ + { name = "boto3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "coverage", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "mypy", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opensandbox", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pre-commit", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pytest", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pytest-asyncio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pytest-cov", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "pytest-xdist", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "requests-mock", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "ruff", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "tenacity", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] dev = [ { name = "coverage", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "mypy", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, @@ -3185,6 +3766,8 @@ dev = [ { name = "ruff", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] sandbox = [ + { name = "boto3", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "daytona", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "opensandbox", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "tenacity", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] @@ -3205,10 +3788,12 @@ docs = [ [package.metadata] requires-dist = [ - { name = "aiohttp", specifier = ">=3.13.3" }, + { name = "aiohttp", specifier = ">=3.14.1" }, { name = "anthropic", specifier = "<=0.109.2" }, + { name = "boto3", marker = "extra == 'sandbox'", specifier = ">=1.34" }, { name = "coverage", extras = ["toml"], marker = "extra == 'dev'" }, { name = "datasets" }, + { name = "daytona", marker = "extra == 'sandbox'", specifier = ">=0.179.0" }, { name = "devtools" }, { name = "fastapi" }, { name = "fonttools", specifier = ">=4.60.2" }, @@ -3220,6 +3805,7 @@ requires-dist = [ { name = "mlflow", specifier = ">=3.14.0" }, { name = "mlflow-skinny", specifier = ">=3.14.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.8.0" }, + { name = "nemo-gym", extras = ["dev", "sandbox"], marker = "extra == 'all'", editable = "3rdparty/Gym-workspace/Gym" }, { name = "omegaconf" }, { name = "openai", specifier = "<=2.7.2" }, { name = "opensandbox", marker = "extra == 'sandbox'", specifier = ">=0.1.9" }, @@ -3246,7 +3832,7 @@ requires-dist = [ { name = "wandb" }, { name = "yappi" }, ] -provides-extras = ["sandbox", "dev"] +provides-extras = ["all", "sandbox", "dev"] [package.metadata.requires-dev] docs = [ @@ -3604,10 +4190,24 @@ version = "1.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/73/79a0b22fc731989c708068427579e840a6cf4e937fe7ae5c5d0b7356ac22/ninja-1.13.0.tar.gz", hash = "sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978", size = 242558, upload-time = "2025-08-11T15:10:19.421Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/74/d02409ed2aa865e051b7edda22ad416a39d81a84980f544f8de717cab133/ninja-1.13.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1", size = 310125, upload-time = "2025-08-11T15:09:50.971Z" }, { url = "https://files.pythonhosted.org/packages/8e/de/6e1cd6b84b412ac1ef327b76f0641aeb5dcc01e9d3f9eee0286d0c34fd93/ninja-1.13.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630", size = 177467, upload-time = "2025-08-11T15:09:52.767Z" }, + { url = "https://files.pythonhosted.org/packages/c8/83/49320fb6e58ae3c079381e333575fdbcf1cca3506ee160a2dcce775046fa/ninja-1.13.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c", size = 187834, upload-time = "2025-08-11T15:09:54.115Z" }, + { url = "https://files.pythonhosted.org/packages/56/c7/ba22748fb59f7f896b609cd3e568d28a0a367a6d953c24c461fe04fc4433/ninja-1.13.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e", size = 202736, upload-time = "2025-08-11T15:09:55.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/22/d1de07632b78ac8e6b785f41fa9aad7a978ec8c0a1bf15772def36d77aac/ninja-1.13.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988", size = 179034, upload-time = "2025-08-11T15:09:57.394Z" }, { url = "https://files.pythonhosted.org/packages/ed/de/0e6edf44d6a04dabd0318a519125ed0415ce437ad5a1ec9b9be03d9048cf/ninja-1.13.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa", size = 180716, upload-time = "2025-08-11T15:09:58.696Z" }, + { url = "https://files.pythonhosted.org/packages/54/28/938b562f9057aaa4d6bfbeaa05e81899a47aebb3ba6751e36c027a7f5ff7/ninja-1.13.0-py3-none-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1", size = 146843, upload-time = "2025-08-11T15:10:00.046Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fb/d06a3838de4f8ab866e44ee52a797b5491df823901c54943b2adb0389fbb/ninja-1.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2", size = 154402, upload-time = "2025-08-11T15:10:01.657Z" }, { url = "https://files.pythonhosted.org/packages/31/bf/0d7808af695ceddc763cf251b84a9892cd7f51622dc8b4c89d5012779f06/ninja-1.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f", size = 552388, upload-time = "2025-08-11T15:10:03.349Z" }, + { url = "https://files.pythonhosted.org/packages/9d/70/c99d0c2c809f992752453cce312848abb3b1607e56d4cd1b6cded317351a/ninja-1.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714", size = 472501, upload-time = "2025-08-11T15:10:04.735Z" }, + { url = "https://files.pythonhosted.org/packages/9f/43/c217b1153f0e499652f5e0766da8523ce3480f0a951039c7af115e224d55/ninja-1.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72", size = 638280, upload-time = "2025-08-11T15:10:06.512Z" }, + { url = "https://files.pythonhosted.org/packages/8c/45/9151bba2c8d0ae2b6260f71696330590de5850e5574b7b5694dce6023e20/ninja-1.13.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db", size = 642420, upload-time = "2025-08-11T15:10:08.35Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/95752eb635bb8ad27d101d71bef15bc63049de23f299e312878fc21cb2da/ninja-1.13.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5", size = 585106, upload-time = "2025-08-11T15:10:09.818Z" }, + { url = "https://files.pythonhosted.org/packages/c1/31/aa56a1a286703800c0cbe39fb4e82811c277772dc8cd084f442dd8e2938a/ninja-1.13.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96", size = 707138, upload-time = "2025-08-11T15:10:11.366Z" }, { url = "https://files.pythonhosted.org/packages/34/6f/5f5a54a1041af945130abdb2b8529cbef0cdcbbf9bcf3f4195378319d29a/ninja-1.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200", size = 581758, upload-time = "2025-08-11T15:10:13.295Z" }, + { url = "https://files.pythonhosted.org/packages/95/97/51359c77527d45943fe7a94d00a3843b81162e6c4244b3579fe8fc54cb9c/ninja-1.13.0-py3-none-win32.whl", hash = "sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9", size = 267201, upload-time = "2025-08-11T15:10:15.158Z" }, + { url = "https://files.pythonhosted.org/packages/29/45/c0adfbfb0b5895aa18cec400c535b4f7ff3e52536e0403602fc1a23f7de9/ninja-1.13.0-py3-none-win_amd64.whl", hash = "sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e", size = 309975, upload-time = "2025-08-11T15:10:16.697Z" }, + { url = "https://files.pythonhosted.org/packages/df/93/a7b983643d1253bb223234b5b226e69de6cda02b76cdca7770f684b795f5/ninja-1.13.0-py3-none-win_arm64.whl", hash = "sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9", size = 290806, upload-time = "2025-08-11T15:10:18.018Z" }, ] [[package]] @@ -3641,8 +4241,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/49/61/7299643b9c18d669e04be7c5bcb64d985070d07553274817b45b049e7bfe/numba-0.65.0.tar.gz", hash = "sha256:edad0d9f6682e93624c00125a471ae4df186175d71fd604c983c377cdc03e68b", size = 2764131, upload-time = "2026-04-01T03:52:01.946Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/f8/eee0f1ff456218db036bfc9023995ec1f85a9dc8f2422f1594f6a87829e0/numba-0.65.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:c6334094563a456a695c812e6846288376ca02327cf246cdcc83e1bb27862367", size = 2680679, upload-time = "2026-04-01T03:51:39.491Z" }, { url = "https://files.pythonhosted.org/packages/1b/8f/3d116e4b8e92f6abace431afa4b2b944f4d65bdee83af886f5c4b263df95/numba-0.65.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b8a9008411615c69d083d1dcf477f75a5aa727b30beb16e139799e2be945cdfd", size = 3809537, upload-time = "2026-04-01T03:51:41.42Z" }, { url = "https://files.pythonhosted.org/packages/b5/2c/6a3ca4128e253cb67affe06deb47688f51ce968f5111e2a06d010e6f1fa6/numba-0.65.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af96c0cba53664efcb361528b8c75e011a6556c859c7e08424c2715201c6cf7a", size = 3508615, upload-time = "2026-04-01T03:51:43.444Z" }, + { url = "https://files.pythonhosted.org/packages/96/0e/267f9a36fb282c104a971d7eecb685b411c47dce2a740fe69cf5fc2945d9/numba-0.65.0-cp313-cp313-win_amd64.whl", hash = "sha256:6254e73b9c929dc736a1fbd3d6f5680789709a5067cae1fa7198707385129c04", size = 2749938, upload-time = "2026-04-01T03:51:45.218Z" }, ] [[package]] @@ -3651,14 +4253,27 @@ version = "2.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1d/d0a583ce4fefcc3308806a749a536c201ed6b5ad6e1322e227ee4848979d/numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50", size = 16684933, upload-time = "2026-03-29T13:19:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/c1/62/2b7a48fbb745d344742c0277f01286dead15f3f68e4f359fbfcf7b48f70f/numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115", size = 14694532, upload-time = "2026-03-29T13:19:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/499737bfba066b4a3bebff24a8f1c5b2dee410b209bc6668c9be692580f0/numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af", size = 5199661, upload-time = "2026-03-29T13:19:28.31Z" }, + { url = "https://files.pythonhosted.org/packages/cd/da/464d551604320d1491bc345efed99b4b7034143a85787aab78d5691d5a0e/numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c", size = 6547539, upload-time = "2026-03-29T13:19:30.97Z" }, { url = "https://files.pythonhosted.org/packages/7d/90/8d23e3b0dafd024bf31bdec225b3bb5c2dbfa6912f8a53b8659f21216cbf/numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103", size = 15668806, upload-time = "2026-03-29T13:19:33.887Z" }, { url = "https://files.pythonhosted.org/packages/d1/73/a9d864e42a01896bb5974475438f16086be9ba1f0d19d0bb7a07427c4a8b/numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83", size = 16632682, upload-time = "2026-03-29T13:19:37.336Z" }, { url = "https://files.pythonhosted.org/packages/34/fb/14570d65c3bde4e202a031210475ae9cde9b7686a2e7dc97ee67d2833b35/numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed", size = 17019810, upload-time = "2026-03-29T13:19:40.963Z" }, { url = "https://files.pythonhosted.org/packages/8a/77/2ba9d87081fd41f6d640c83f26fb7351e536b7ce6dd9061b6af5904e8e46/numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959", size = 18357394, upload-time = "2026-03-29T13:19:44.859Z" }, + { url = "https://files.pythonhosted.org/packages/a2/23/52666c9a41708b0853fa3b1a12c90da38c507a3074883823126d4e9d5b30/numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed", size = 5959556, upload-time = "2026-03-29T13:19:47.661Z" }, + { url = "https://files.pythonhosted.org/packages/57/fb/48649b4971cde70d817cf97a2a2fdc0b4d8308569f1dd2f2611959d2e0cf/numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf", size = 12317311, upload-time = "2026-03-29T13:19:50.67Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/11490cddd564eb4de97b4579ef6bfe6a736cc07e94c1598590ae25415e01/numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d", size = 10222060, upload-time = "2026-03-29T13:19:54.229Z" }, + { url = "https://files.pythonhosted.org/packages/99/5d/dab4339177a905aad3e2221c915b35202f1ec30d750dd2e5e9d9a72b804b/numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5", size = 14822302, upload-time = "2026-03-29T13:19:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e4/0564a65e7d3d97562ed6f9b0fd0fb0a6f559ee444092f105938b50043876/numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7", size = 5327407, upload-time = "2026-03-29T13:20:00.601Z" }, + { url = "https://files.pythonhosted.org/packages/29/8d/35a3a6ce5ad371afa58b4700f1c820f8f279948cca32524e0a695b0ded83/numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93", size = 6647631, upload-time = "2026-03-29T13:20:02.855Z" }, { url = "https://files.pythonhosted.org/packages/f4/da/477731acbd5a58a946c736edfdabb2ac5b34c3d08d1ba1a7b437fa0884df/numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e", size = 15727691, upload-time = "2026-03-29T13:20:06.004Z" }, { url = "https://files.pythonhosted.org/packages/e6/db/338535d9b152beabeb511579598418ba0212ce77cf9718edd70262cc4370/numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40", size = 16681241, upload-time = "2026-03-29T13:20:09.417Z" }, { url = "https://files.pythonhosted.org/packages/e2/a9/ad248e8f58beb7a0219b413c9c7d8151c5d285f7f946c3e26695bdbbe2df/numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e", size = 17085767, upload-time = "2026-03-29T13:20:13.126Z" }, { url = "https://files.pythonhosted.org/packages/b5/1a/3b88ccd3694681356f70da841630e4725a7264d6a885c8d442a697e1146b/numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392", size = 18403169, upload-time = "2026-03-29T13:20:17.096Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" }, + { url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" }, ] [[package]] @@ -3682,6 +4297,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/9c/da/45f78bb61f93a467ccaccf2eafbf23483bdcb29d3c5d16f8cb918be1aea0/nvidia_cublas-13.5.1.27-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bc355b10e35b01cf88e8dcc0fbe0fd1ef86a05fddae78a44dc133d7e63eaf973", size = 515580892, upload-time = "2026-05-26T16:43:17.967Z" }, { url = "https://files.pythonhosted.org/packages/ce/0d/cc77458e8fb0634597e3994650c2853ee785f2fc61bf370bbb304021cca1/nvidia_cublas-13.5.1.27-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:db3a1f0c8bc24945a4d195ba199d83f27e650ffdfc0c32e6b8362c314f14d553", size = 407748877, upload-time = "2026-05-26T16:44:19.938Z" }, + { url = "https://files.pythonhosted.org/packages/99/73/2c08fc3802d72931af348e8f1cf3a0b013e5dd91a6dcc235af8f52cfcb87/nvidia_cublas-13.5.1.27-py3-none-win_amd64.whl", hash = "sha256:234a2e89682080421431d2f2ea422fc2ad7d0b462336ccdfde76c559c906c670", size = 391875500, upload-time = "2026-05-26T17:06:29.178Z" }, ] [[package]] @@ -3691,6 +4307,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/7a/9cb8a7fb87a85b11e8753548ae1422be847c5dddf3ca9ff5b080b309e271/nvidia_cuda_cccl-13.3.3.3.1-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4dbc9dd84fbaeae267cbd80a9ed76d35171dba78639695dbdff0bae50e4503fa", size = 3453010, upload-time = "2026-05-26T16:27:45.179Z" }, { url = "https://files.pythonhosted.org/packages/fe/fb/195d50d25ab68a76b817ffc68c45b1fb828598ce35a8e5c1736060628dab/nvidia_cuda_cccl-13.3.3.3.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40ba1fa0b2c694ddc06cc791ed5c8bdad4638e2735b784960d68ac3086399c97", size = 3453013, upload-time = "2026-05-26T16:28:08.209Z" }, + { url = "https://files.pythonhosted.org/packages/57/44/37cf1596880e7712f357b3f4991cd34d0f322c26e2bc814d1bdeffb2f420/nvidia_cuda_cccl-13.3.3.3.1-py3-none-win_amd64.whl", hash = "sha256:d1ac746f57ab83403f01e64e2b292101caf5b3445babca9f1c1c34f344766adf", size = 3452993, upload-time = "2026-05-26T16:58:59.166Z" }, ] [[package]] @@ -3700,6 +4317,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151", size = 10310827, upload-time = "2025-09-04T08:26:42.012Z" }, { url = "https://files.pythonhosted.org/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8", size = 10715597, upload-time = "2025-09-04T08:26:51.312Z" }, + { url = "https://files.pythonhosted.org/packages/ad/df/b74b10025c1205695c5676373f2edd3e87a7202cc62ead0dfbc373b0f6ea/nvidia_cuda_cupti-13.0.85-py3-none-win_amd64.whl", hash = "sha256:683f58d301548deeefcb8f6fac1b8d907691b9d8b18eccab417f51e362102f00", size = 7736776, upload-time = "2025-09-04T08:38:08.38Z" }, ] [[package]] @@ -3709,6 +4327,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575", size = 90215200, upload-time = "2025-09-04T08:28:44.204Z" }, { url = "https://files.pythonhosted.org/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b", size = 43015449, upload-time = "2025-09-04T08:28:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/4a/af/345fedb9f4c76c84ab4fa445b36bd4048a4d9db60e6bc76b4f913ff4b852/nvidia_cuda_nvrtc-13.0.88-py3-none-win_amd64.whl", hash = "sha256:6bcd4e7f8e205cbe644f5a98f2f799bef9556fefc89dd786e79a16312ce49872", size = 76807835, upload-time = "2025-09-04T08:39:15.274Z" }, ] [[package]] @@ -3718,6 +4337,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55", size = 2261060, upload-time = "2025-10-09T08:55:15.78Z" }, { url = "https://files.pythonhosted.org/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548", size = 2243632, upload-time = "2025-10-09T08:55:36.117Z" }, + { url = "https://files.pythonhosted.org/packages/b7/94/6b867483bec07da24ffa32736c79fabb94ef3a7af4d787a9d4a974868576/nvidia_cuda_runtime-13.0.96-py3-none-win_amd64.whl", hash = "sha256:f79298c8a098cec150a597c8eba58ecdab96e3bdc4b9bc4f9983635031740492", size = 2927037, upload-time = "2025-10-09T09:04:23.782Z" }, ] [[package]] @@ -3730,6 +4350,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/56/c5/83384d846b2fd17c44bd499b36c75a45ed4f095fbbb2252294e89cea5c5c/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e31454ae00094b0c55319d9d15b6fa2fc50a9e1c0f5c8c80fb75258234e731e1", size = 444574296, upload-time = "2026-03-09T19:28:27.751Z" }, { url = "https://files.pythonhosted.org/packages/6e/5e/edb9c0ae051602c3ccaffe424256463636d639e27d7f302dde9975ef9e7a/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0c45dd8eeb50b603f07995b1b300c62ffe6a1980482b82b3bcf94a4ca9d49304", size = 366173588, upload-time = "2026-03-09T19:29:34.474Z" }, + { url = "https://files.pythonhosted.org/packages/78/39/21507455b1bca8b5702a9e9fc6ce73735f216f558dac2c9ede58e4d456b8/nvidia_cudnn_cu13-9.20.0.48-py3-none-win_amd64.whl", hash = "sha256:af8139732b99c0118be65ea5aac97f0d46018f8c552889e49d2fb0c6261a4a24", size = 350712614, upload-time = "2026-03-09T19:31:11.398Z" }, ] [[package]] @@ -3739,6 +4360,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/55/bc/eed9ae32a00a7c501f6ca3b93782fe50b3c9fd9168d500586b761f42f2bd/nvidia_cudnn_frontend-1.23.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa35283da087d65cdc1ea12a7872f90ed5a725e8ed0d8009b82d801bf92ad0ae", size = 2935910, upload-time = "2026-04-29T19:15:20.96Z" }, { url = "https://files.pythonhosted.org/packages/ad/14/4e0b66650d68f32d4c7b46e8b33cb98e69497f3fc1a9f63a02328a45d694/nvidia_cudnn_frontend-1.23.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8b817a0deb94f394b082f1ca389829ec0c9c85411a1092f08719c66bbaa1e39", size = 3082233, upload-time = "2026-04-29T19:15:48.864Z" }, + { url = "https://files.pythonhosted.org/packages/e3/c8/f5fad0e91e43df3a85e7c29b15bd11b587f27a096b7096abd3b3fbc8f761/nvidia_cudnn_frontend-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:b78c70b40c389f9e844eae73f5686bb72b15763399aede5c3995d81e78c5547c", size = 2494849, upload-time = "2026-04-29T19:16:11.571Z" }, ] [[package]] @@ -3751,6 +4373,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, { url = "https://files.pythonhosted.org/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3", size = 214085489, upload-time = "2025-09-04T08:31:56.044Z" }, + { url = "https://files.pythonhosted.org/packages/85/b2/f8af21a2ed1beed337a6a02c5a28aeb85441f4d578ec3d529543c775ea4b/nvidia_cufft-12.0.0.61-py3-none-win_amd64.whl", hash = "sha256:2abce5b39d2f5ae12730fb7e5db6696533e36c26e2d3e8fd1750bdd2853364eb", size = 213342123, upload-time = "2025-09-04T08:40:51.145Z" }, ] [[package]] @@ -3769,6 +4392,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a", size = 61962106, upload-time = "2025-08-04T10:21:41.128Z" }, { url = "https://files.pythonhosted.org/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc", size = 59544258, upload-time = "2025-08-04T10:22:03.992Z" }, + { url = "https://files.pythonhosted.org/packages/99/27/72103153b1ffc00e09fdc40ac970235343dcd1ea8bd762e84d2d73219ffa/nvidia_curand-10.4.0.35-py3-none-win_amd64.whl", hash = "sha256:65b1710aa6961d326b411e314b374290904c5ddf41dc3f766ebc3f1d7d4ca69f", size = 55242481, upload-time = "2025-08-04T10:30:41.831Z" }, ] [[package]] @@ -3783,6 +4407,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, { url = "https://files.pythonhosted.org/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112", size = 200941980, upload-time = "2025-09-04T08:33:22.767Z" }, + { url = "https://files.pythonhosted.org/packages/99/ef/332a0101260ca78a1daef046bf0b06199e8ed4dac1d2aa698289c358169c/nvidia_cusolver-12.0.4.66-py3-none-win_amd64.whl", hash = "sha256:16515bd33a8e76bb54d024cfa068fa68d30e80fc34b9e1090813ea9362e0cb65", size = 193551444, upload-time = "2025-09-04T08:41:46.813Z" }, ] [[package]] @@ -3795,6 +4420,7 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, { url = "https://files.pythonhosted.org/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b", size = 145942937, upload-time = "2025-09-04T08:33:58.029Z" }, + { url = "https://files.pythonhosted.org/packages/02/b0/b043d6f3480f102f885cf87fc3ffd3edcb5e23b855025a50e2ef4d059185/nvidia_cusparse-12.6.3.3-py3-none-win_amd64.whl", hash = "sha256:cbcf42feb737bd7ec15b4c0a63e62351886bd3f975027b8815d7f720a2b5ea79", size = 143783033, upload-time = "2025-09-04T08:42:12.391Z" }, ] [[package]] @@ -3804,6 +4430,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/46/10/8dcd1175260706a2fc92a16a52e306b71d4c1ea0b0cc4a9484183399818a/nvidia_cusparselt_cu13-0.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:400c6ed1cf6780fc6efedd64ec9f1345871767e6a1a0a552a1ea0578117ea77c", size = 220791277, upload-time = "2025-08-13T19:22:40.982Z" }, { url = "https://files.pythonhosted.org/packages/fd/53/43b0d71f4e702fa9733f8b4571fdca50a8813f1e450b656c239beff12315/nvidia_cusparselt_cu13-0.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:25e30a8a7323935d4ad0340b95a0b69926eee755767e8e0b1cf8dd85b197d3fd", size = 169884119, upload-time = "2025-08-13T19:23:41.967Z" }, + { url = "https://files.pythonhosted.org/packages/57/de/8f0578928b9b1246d7b1324db0528e6b9f9fb54496a49f40bf71f09f1a27/nvidia_cusparselt_cu13-0.8.0-py3-none-win_amd64.whl", hash = "sha256:e80212ed7b1afc97102fbb2b5c82487aa73f6a0edfa6d26c5a152593e520bb8f", size = 156459710, upload-time = "2025-08-13T19:24:18.043Z" }, ] [[package]] @@ -3898,6 +4525,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/56/7a/123e033aaff487c77107195fa5a2b8686795ca537935a24efae476c41f05/nvidia_nvjitlink-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:13a74f429e23b921c1109976abefacc69835f2f433ebd323d3946e11d804e47b", size = 40713933, upload-time = "2025-09-04T08:35:43.553Z" }, { url = "https://files.pythonhosted.org/packages/ab/2c/93c5250e64df4f894f1cbb397c6fd71f79813f9fd79d7cd61de3f97b3c2d/nvidia_nvjitlink-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e931536ccc7d467a98ba1d8b89ff7fa7f1fa3b13f2b0069118cd7f47bff07d0c", size = 38768748, upload-time = "2025-09-04T08:35:20.008Z" }, + { url = "https://files.pythonhosted.org/packages/e4/01/07530b0e37546231052e30234540289c42eaffa486f1a34a87fed340157b/nvidia_nvjitlink-13.0.88-py3-none-win_amd64.whl", hash = "sha256:634e96e3da9ef845ae744097a1f289238ecf946ce0b82e93cdce14b9782e682f", size = 36035115, upload-time = "2025-09-04T08:43:03.001Z" }, ] [[package]] @@ -3919,6 +4547,7 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4", size = 148047, upload-time = "2025-09-04T08:29:01.761Z" }, { url = "https://files.pythonhosted.org/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6", size = 148878, upload-time = "2025-09-04T08:28:53.627Z" }, + { url = "https://files.pythonhosted.org/packages/d2/50/0e2220f8620a177de994211186ffc5bfa9f2ce1e1282797f8f90096f9f88/nvidia_nvtx-13.0.85-py3-none-win_amd64.whl", hash = "sha256:d66ea44254dd3c6eacc300047af6e1288d2269dd072b417e0adffbf479e18519", size = 137066, upload-time = "2025-09-04T08:39:25.649Z" }, ] [[package]] @@ -3976,8 +4605,31 @@ sdist = { url = "https://files.pythonhosted.org/packages/92/dd/692765e87de30bae1 wheels = [ { url = "https://files.pythonhosted.org/packages/05/c9/8341224b8284f7deb6a634119939de5885adc421e64b6743693b30da2186/nvtx-0.2.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d28660d9c46f8ba750d781572b6aa5a1e6221abba224ab32d7fb32c2d0fd67df", size = 780787, upload-time = "2026-03-18T10:10:40.634Z" }, { url = "https://files.pythonhosted.org/packages/b1/c0/4a5bb7897918de7c7e0191d9342df8ae4cb797ff07276e0f20d13e497ce7/nvtx-0.2.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10749686633f880ad53dcdbb2179fad41b45dcf5b7631d4a1070a577577bd386", size = 782575, upload-time = "2026-03-18T10:13:57.3Z" }, + { url = "https://files.pythonhosted.org/packages/38/b9/6b381ac7c5a3ded331aebbf25f8959d19b51d320fb2514c76c6b6edddaaa/nvtx-0.2.15-cp313-cp313-win_amd64.whl", hash = "sha256:a6650b029263d12f8427a4dee8bd59cb9c91bccb60543bfcb20bc2b00fdcd672", size = 128764, upload-time = "2026-03-18T10:02:33.343Z" }, { url = "https://files.pythonhosted.org/packages/75/69/a9acb6d95d2e0e381b2956544768528dd8d7a9e827af8c2014169d838284/nvtx-0.2.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25813ead4fff4d3a6e04f69a72507b096a6bdbecefa369f1100b0e584767bca8", size = 833375, upload-time = "2026-03-18T10:06:31.955Z" }, { url = "https://files.pythonhosted.org/packages/38/56/c7e8645061cc2fc23f3a54f33e1e340df59216f07dcfb97d46b8ae7dd26c/nvtx-0.2.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3741edac4678b92f03d22a3f0a2dfd469f422f85e63db71b038e02525b2404ad", size = 788639, upload-time = "2026-03-18T10:12:01.69Z" }, + { url = "https://files.pythonhosted.org/packages/96/03/fadd82acdbca6d1c49ac517081a0c3714346f52f4c7e1d4449d77605b4aa/nvtx-0.2.15-cp313-cp313t-win_amd64.whl", hash = "sha256:8be06c3c8c267eba56a0396366b9593092e0b75ea8d3702b303d48c0a1662f0e", size = 142609, upload-time = "2026-03-18T10:01:48.832Z" }, +] + +[[package]] +name = "obstore" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/2f/f83afaab7945509d72245b2b00af0b4834ce78fdd2d9ae9f0ad1a3036a91/obstore-0.11.0.tar.gz", hash = "sha256:a2f55163bcd348b4a60d12e6893eac50eddc742bad8032a1705d49140b992204", size = 130565, upload-time = "2026-06-25T18:29:49.405Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/b2/00c213e7e5ca8065f97e37e55294adab836e3f6a88b23e4029069aaecf95/obstore-0.11.0-cp311-abi3-macosx_10_12_x86_64.whl", hash = "sha256:42f36546c7ac44dbab1173d2330a8a1b1a3f0e37950e553b8c904e3dd0744b25", size = 5491935, upload-time = "2026-06-25T18:28:32.029Z" }, + { url = "https://files.pythonhosted.org/packages/ac/37/6a6b9a5e15a8a37c24d14317a87648097c4888593b588510c03c030d2e90/obstore-0.11.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:687bb9d3962d568b7c439c5d0c6fea19b2749862a8e5c8eebd0c058c4eccde9e", size = 4672619, upload-time = "2026-06-25T18:28:33.852Z" }, + { url = "https://files.pythonhosted.org/packages/28/f9/6745ce8c4f7bfac19dc14a4438b48a2e93a689b92b0cecfc695e41a4e8b1/obstore-0.11.0-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:010b51578c7514a41719d795cdb7a1e6529be509dac3772e477187a59422bb97", size = 5072806, upload-time = "2026-06-25T18:28:36.127Z" }, + { url = "https://files.pythonhosted.org/packages/6c/18/991d3b3cdd851c0225e55f3dc45b47fd9e249827d188995011469f805132/obstore-0.11.0-cp311-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfaa8129a3f5d8518a3a75184d4b02348db0f6263177cd1f0951f6568243cc9e", size = 5303777, upload-time = "2026-06-25T18:28:37.89Z" }, + { url = "https://files.pythonhosted.org/packages/8d/e9/90e56015a45b5e56a84fc3188c4e5fb088b288d41992c73a629e10df6760/obstore-0.11.0-cp311-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c790a5cb9ff2970d1f464a6a708d734dce9939e9f668cb6708c5dba5d61589b2", size = 5493871, upload-time = "2026-06-25T18:28:39.981Z" }, + { url = "https://files.pythonhosted.org/packages/66/02/f1744091d59ce71c5523174eb860fbb298275c901e89b9ea6fbf3e654a33/obstore-0.11.0-cp311-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:827113e12fe8088e0281a9d57b90b2b8dbc8a6ffe3b15dadb9baa5feb3d266c1", size = 5361913, upload-time = "2026-06-25T18:28:42.089Z" }, + { url = "https://files.pythonhosted.org/packages/5d/59/3f47822683ee2b6db8685faa25829946d6343a561251ec2704548455d946/obstore-0.11.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2ff6d3ed553298828fb760b4aef6347fbcc7b5c5e3ce3f8381ce805c370021a", size = 5638724, upload-time = "2026-06-25T18:28:43.897Z" }, + { url = "https://files.pythonhosted.org/packages/23/50/1df335fdf9b527b3933f1e94ab6fc720ad314260fab8591cb0b6668ff192/obstore-0.11.0-cp311-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:39d04b324fcf984e7050734ebda77b81764025b0c011750201a0d8954087f7aa", size = 5413508, upload-time = "2026-06-25T18:28:45.624Z" }, + { url = "https://files.pythonhosted.org/packages/de/dc/a259aba149b841ca7c91fea177df9972a60a636b54077beed1a35b254994/obstore-0.11.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:37c0d15d775b1370ef5204ee3919a5ddf7e2592d11815213105f8db031f2ab8d", size = 5619995, upload-time = "2026-06-25T18:28:47.599Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b4/ec25fdb4d6b060bc6eea647fc0e88f75fcc20fe8d16d67fb0dbe999d323b/obstore-0.11.0-cp311-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:7f468caf9b6e0f12ff151e5fe618de5fc9192befa9bd02734b06de4efd2e49f6", size = 5299512, upload-time = "2026-06-25T18:28:49.629Z" }, + { url = "https://files.pythonhosted.org/packages/a8/e5/29be060d06ec13e2af3d1b6cfb77b7c37f8be6c56b77295c945fefad73e4/obstore-0.11.0-cp311-abi3-musllinux_1_2_i686.whl", hash = "sha256:42d8e8fad85be8ee488c1a9a9b7c6a42128abb84e67175da40d3d1165c1846df", size = 5427026, upload-time = "2026-06-25T18:28:51.317Z" }, + { url = "https://files.pythonhosted.org/packages/57/b7/577a965f440e9ea64243518663f9d16be7df8eafc7123818e8e841fa21ce/obstore-0.11.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9c8fd2a544e2e0b926669c47fcfb8d2314e234abc240ea165dae04ee42e1d7ac", size = 5869187, upload-time = "2026-06-25T18:28:53.166Z" }, + { url = "https://files.pythonhosted.org/packages/e2/18/8fdbaee22bfd5b9c44e1fdff8ca0508e2fe60c42bf9fc85f0c9c27b4ecf2/obstore-0.11.0-cp311-abi3-win_amd64.whl", hash = "sha256:6fb3d4678c0f4242d3109362e9b1df5d7b27765f43d5aacb2e81af53a75cb9ef", size = 5329384, upload-time = "2026-06-25T18:28:55.305Z" }, ] [[package]] @@ -4005,10 +4657,17 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/c5/93/942d2a0f6a70538eea042ce0445c8aefd46559ad153469986f29a743c01c/onnx-1.21.0.tar.gz", hash = "sha256:4d8b67d0aaec5864c87633188b91cc520877477ec0254eda122bef8be43cd764", size = 12074608, upload-time = "2026-03-27T21:33:36.118Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/ae/cb644ec84c25e63575d9d8790fdcc5d1a11d67d3f62f872edb35fa38d158/onnx-1.21.0-cp312-abi3-macosx_12_0_universal2.whl", hash = "sha256:fc2635400fe39ff37ebc4e75342cc54450eadadf39c540ff132c319bf4960095", size = 17965930, upload-time = "2026-03-27T21:32:48.089Z" }, { url = "https://files.pythonhosted.org/packages/6f/b6/eeb5903586645ef8a49b4b7892580438741acc3df91d7a5bd0f3a59ea9cb/onnx-1.21.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9003d5206c01fa2ff4b46311566865d8e493e1a6998d4009ec6de39843f1b59b", size = 17531344, upload-time = "2026-03-27T21:32:50.837Z" }, { url = "https://files.pythonhosted.org/packages/a7/00/4823f06357892d1e60d6f34e7299d2ba4ed2108c487cc394f7ce85a3ff14/onnx-1.21.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9261bd580fb8548c9c37b3c6750387eb8f21ea43c63880d37b2c622e1684285", size = 17613697, upload-time = "2026-03-27T21:32:54.222Z" }, + { url = "https://files.pythonhosted.org/packages/23/1d/391f3c567ae068c8ac4f1d1316bae97c9eb45e702f05975fe0e17ad441f0/onnx-1.21.0-cp312-abi3-win32.whl", hash = "sha256:9ea4e824964082811938a9250451d89c4ec474fe42dd36c038bfa5df31993d1e", size = 16287200, upload-time = "2026-03-27T21:32:57.277Z" }, + { url = "https://files.pythonhosted.org/packages/9c/a6/5eefbe5b40ea96de95a766bd2e0e751f35bdea2d4b951991ec9afaa69531/onnx-1.21.0-cp312-abi3-win_amd64.whl", hash = "sha256:458d91948ad9a7729a347550553b49ab6939f9af2cddf334e2116e45467dc61f", size = 16441045, upload-time = "2026-03-27T21:33:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/63/c4/0ed8dc037a39113d2a4d66e0005e07751c299c46b993f1ad5c2c35664c20/onnx-1.21.0-cp312-abi3-win_arm64.whl", hash = "sha256:ca14bc4842fccc3187eb538f07eabeb25a779b39388b006db4356c07403a7bbb", size = 16403134, upload-time = "2026-03-27T21:33:03.987Z" }, + { url = "https://files.pythonhosted.org/packages/f8/89/0e1a9beb536401e2f45ac88735e123f2735e12fc7b56ff6c11727e097526/onnx-1.21.0-cp313-cp313t-macosx_12_0_universal2.whl", hash = "sha256:257d1d1deb6a652913698f1e3f33ef1ca0aa69174892fe38946d4572d89dd94f", size = 17975430, upload-time = "2026-03-27T21:33:07.005Z" }, { url = "https://files.pythonhosted.org/packages/ec/46/e6dc71a7b3b317265591b20a5f71d0ff5c0d26c24e52283139dc90c66038/onnx-1.21.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7cd7cb8f6459311bdb557cbf6c0ccc6d8ace11c304d1bba0a30b4a4688e245f8", size = 17537435, upload-time = "2026-03-27T21:33:09.765Z" }, { url = "https://files.pythonhosted.org/packages/49/2e/27affcac63eaf2ef183a44fd1a1354b11da64a6c72fe6f3fdcf5571bcee5/onnx-1.21.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b58a4cfec8d9311b73dc083e4c1fa362069267881144c05139b3eba5dc3a840", size = 17617687, upload-time = "2026-03-27T21:33:12.619Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5c/ac8ed15e941593a3672ce424280b764979026317811f2e8508432bfc3429/onnx-1.21.0-cp313-cp313t-win_amd64.whl", hash = "sha256:1a9baf882562c4cebf79589bebb7cd71a20e30b51158cac3e3bbaf27da6163bd", size = 16449402, upload-time = "2026-03-27T21:33:15.555Z" }, + { url = "https://files.pythonhosted.org/packages/0e/aa/d2231e0dcaad838217afc64c306c8152a080134d2034e247cc973d577674/onnx-1.21.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bba12181566acf49b35875838eba49536a327b2944664b17125577d230c637ad", size = 16408273, upload-time = "2026-03-27T21:33:18.599Z" }, ] [[package]] @@ -4091,10 +4750,19 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/92/94/01509d510bebf6606614e51113e5a415ced15b8f34aa98a8bf2539314650/openai_harmony-0.0.4.tar.gz", hash = "sha256:5c67ac6df349236fb7b64f57c3dbb0273efcdca24314daa108f2a482c427106c", size = 279848, upload-time = "2025-08-09T01:43:24.974Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/3e/6bb75a4d15a6aad0ba1b23193ca0d2c202cc1f3364ba840833374b7c9c1a/openai_harmony-0.0.4-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3586d90c899cd41f8624e7b82a48c289f6e4be56c66304ecaf3a0ba88963a73f", size = 2772770, upload-time = "2025-08-09T01:43:14.839Z" }, + { url = "https://files.pythonhosted.org/packages/34/41/2f256fba6762d028ed6f935f0015f71d81927a52b9a1c873679a409b72bf/openai_harmony-0.0.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef21a1e2384a65c62d5ec5e1cded9fe026f1d032d5c5d725110d1a8d330d8f54", size = 2633682, upload-time = "2025-08-09T01:43:12.681Z" }, { url = "https://files.pythonhosted.org/packages/05/88/ade63bd8f36603610040e7cc086bc134d57a99a742e05f7fcddfdf822ee1/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf2344366f10981bbc0f6d9949a0b2bb87151d209ed295943ed6ad8eda37932", size = 2963206, upload-time = "2025-08-09T01:43:02.433Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ef/a65a0ff177fdf67bc0afd18bb9e7ad690d1b553a8eb5ebf27f601b22dbd0/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d8d16d84702059833fb03b841b28c25600c54e83cadccef79af44e1c81166b1", size = 2724854, upload-time = "2025-08-09T01:43:04.606Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a1/ebaf0f55601a98609641283884d52dbfe9a1cf34b04f1cf80acb1560ab74/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97f1fe3909733212cc6b36f0f199b1421a9c57b79ec665f0322bd604cec47340", size = 2984312, upload-time = "2025-08-09T01:43:08.908Z" }, + { url = "https://files.pythonhosted.org/packages/45/24/246f6f470bfbc89a117714b68f27cdaee12b31166237a227cc657780cc1d/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:567cc568b6bf7b4d041b0c9aa7d6b2c9394f8af6065bc87fa6d23f207b5af9a7", size = 3447870, upload-time = "2025-08-09T01:43:06.734Z" }, { url = "https://files.pythonhosted.org/packages/1f/ec/dcdcace0ffcf3a532cca910e0c351b62d3a7decf0b091ea8cf856d2a67a6/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31e9bcac0902a309e2fc688e52f247eec7fffcd00d17e958b9a83a8fea6519c2", size = 3049306, upload-time = "2025-08-09T01:43:11.019Z" }, { url = "https://files.pythonhosted.org/packages/ad/39/172f1048d935db1523a82b45fee5231ad6c622645e566706e6bcf3731da8/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:96a63199c0d81095b5d5d1ae8ca82b64c1c13d18d4e30323ae9e8ab31bc80a3d", size = 3121347, upload-time = "2025-08-09T01:43:16.705Z" }, + { url = "https://files.pythonhosted.org/packages/6b/36/8ee4ca5d0b25587121fd3621e6a6106fba80218cb6d159e1670aeb2b22ef/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:d38f2639f6bf7c3c34a5dfd79e29075811ae2fa9b895a63e76767f74a47a971e", size = 2952326, upload-time = "2025-08-09T01:43:18.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/a0/ec8906393968679e269e23e957e11ff419978d1d077fb9af9561b161c988/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:038f1d6772d1be5213b36ae76e5d042022395ec35c428a73ccb8b839b2cecf6a", size = 3015832, upload-time = "2025-08-09T01:43:21.076Z" }, { url = "https://files.pythonhosted.org/packages/a8/bd/aa9e6e5cf140716dbcae17402fac2a81a9ebb3f934059ac0eec61cb447fc/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:15e6d53a66502491a3675a536df30e271f976e6c5efe68250a65191efcb85c4f", size = 3221129, upload-time = "2025-08-09T01:43:23.146Z" }, + { url = "https://files.pythonhosted.org/packages/5a/22/2c7e1728689c7fa98a259ca2d14e718ea7af964516a617a9784f0d35d88a/openai_harmony-0.0.4-cp38-abi3-win32.whl", hash = "sha256:b9ee9e9ab6a237cebbe16563c787a6e83f3fcc034075c3d321dab94448426282", size = 2077125, upload-time = "2025-08-09T01:43:28.91Z" }, + { url = "https://files.pythonhosted.org/packages/e7/93/3a08a06ff3bde7f4c264f86d437e6a5c49792a6e362383b3a669f39c9690/openai_harmony-0.0.4-cp38-abi3-win_amd64.whl", hash = "sha256:746f751de5033b3dbcfcd4a726a4c56ce452c593ad3d54472d8597ce8d8b6d44", size = 2444821, upload-time = "2025-08-09T01:43:26.846Z" }, ] [[package]] @@ -4128,10 +4796,14 @@ dependencies = [ { name = "numpy", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, ] wheels = [ + { url = "https://files.pythonhosted.org/packages/79/42/2310883be3b8826ac58c3f2787b9358a2d46923d61f88fedf930bc59c60c/opencv_python_headless-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:1a7d040ac656c11b8c38677cc8cccdc149f98535089dbe5b081e80a4e5903209", size = 46247192, upload-time = "2026-02-05T07:01:35.187Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1e/6f9e38005a6f7f22af785df42a43139d0e20f169eb5787ce8be37ee7fcc9/opencv_python_headless-4.13.0.92-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:3e0a6f0a37994ec6ce5f59e936be21d5d6384a4556f2d2da9c2f9c5dc948394c", size = 32568914, upload-time = "2026-02-05T07:01:51.989Z" }, { url = "https://files.pythonhosted.org/packages/21/76/9417a6aef9def70e467a5bf560579f816148a4c658b7d525581b356eda9e/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c8cfc8e87ed452b5cecb9419473ee5560a989859fe1d10d1ce11ae87b09a2cb", size = 33703709, upload-time = "2026-02-05T10:24:46.469Z" }, { url = "https://files.pythonhosted.org/packages/92/ce/bd17ff5772938267fd49716e94ca24f616ff4cb1ff4c6be13085108037be/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0525a3d2c0b46c611e2130b5fdebc94cf404845d8fa64d2f3a3b679572a5bd22", size = 56016764, upload-time = "2026-02-05T10:26:48.904Z" }, { url = "https://files.pythonhosted.org/packages/8f/b4/b7bcbf7c874665825a8c8e1097e93ea25d1f1d210a3e20d4451d01da30aa/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb60e36b237b1ebd40a912da5384b348df8ed534f6f644d8e0b4f103e272ba7d", size = 35010236, upload-time = "2026-02-05T10:28:11.031Z" }, { url = "https://files.pythonhosted.org/packages/4b/33/b5db29a6c00eb8f50708110d8d453747ca125c8b805bc437b289dbdcc057/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0bd48544f77c68b2941392fcdf9bcd2b9cdf00e98cb8c29b2455d194763cf99e", size = 60391106, upload-time = "2026-02-05T10:30:14.236Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c3/52cfea47cd33e53e8c0fbd6e7c800b457245c1fda7d61660b4ffe9596a7f/opencv_python_headless-4.13.0.92-cp37-abi3-win32.whl", hash = "sha256:a7cf08e5b191f4ebb530791acc0825a7986e0d0dee2a3c491184bd8599848a4b", size = 30812232, upload-time = "2026-02-05T07:02:29.594Z" }, + { url = "https://files.pythonhosted.org/packages/4a/90/b338326131ccb2aaa3c2c85d00f41822c0050139a4bfe723cfd95455bd2d/opencv_python_headless-4.13.0.92-cp37-abi3-win_amd64.whl", hash = "sha256:77a82fe35ddcec0f62c15f2ba8a12ecc2ed4207c17b0902c7a3151ae29f37fb6", size = 40070414, upload-time = "2026-02-05T07:02:26.448Z" }, ] [[package]] @@ -4180,7 +4852,7 @@ name = "opentelemetry-exporter-otlp-proto-common" version = "1.41.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-proto", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "opentelemetry-proto", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/fa/f9e3bd3c4d692b3ce9a2880a167d1f79681a1bea11f00d5bf76adc03e6ea/opentelemetry_exporter_otlp_proto_common-1.41.1.tar.gz", hash = "sha256:0e253156ea9c36b0bd3d2440c5c9ba7dd1f3fb64ba7a08fc85fbac536b56e1fb", size = 20409, upload-time = "2026-04-24T13:15:40.924Z" } wheels = [ @@ -4210,13 +4882,13 @@ name = "opentelemetry-exporter-otlp-proto-http" version = "1.41.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "googleapis-common-protos", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "opentelemetry-api", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "opentelemetry-exporter-otlp-proto-common", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "opentelemetry-proto", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "opentelemetry-sdk", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "requests", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "typing-extensions", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "googleapis-common-protos", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-api", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-exporter-otlp-proto-common", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-proto", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-sdk", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "requests", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/5b/9d3c7f70cca10136ba82a81e738dee626c8e7fc61c6887ea9a58bf34c606/opentelemetry_exporter_otlp_proto_http-1.41.1.tar.gz", hash = "sha256:4747a9604c8550ab38c6fd6180e2fcb80de3267060bef2c306bad3cb443302bc", size = 24139, upload-time = "2026-04-24T13:15:42.977Z" } wheels = [ @@ -4237,6 +4909,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/d2/ee4002b88e20c59fae52bed008a63c6f7eff7d498f302032f6b0434a6de7/opentelemetry_exporter_prometheus-0.62b1-py3-none-any.whl", hash = "sha256:7a0b8a6402e107e1f93e38f074a668797e1103936b189561959531a67ffeba55", size = 13278, upload-time = "2026-04-24T13:15:22.485Z" }, ] +[[package]] +name = "opentelemetry-instrumentation" +version = "0.62b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-semantic-conventions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "packaging", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "wrapt", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/cb/0523b92c112a6cc70be43724343dc45225d3af134419844d7879a07755d4/opentelemetry_instrumentation-0.62b1.tar.gz", hash = "sha256:90e92a905ba4f84db06ac3aec96701df6c079b2d66e9379f8739f0a1bdcc7f45", size = 34043, upload-time = "2026-04-24T13:22:31.997Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/0f/45adbaea1f81b847cffdcee4f4b5f89297e42facf7fac78c7aaac4c38e75/opentelemetry_instrumentation-0.62b1-py3-none-any.whl", hash = "sha256:976fc6e640f2006599e97429c949e622c108d0c17c2059347d1e6c93c707f257", size = 34163, upload-time = "2026-04-24T13:21:31.722Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation-aiohttp-client" +version = "0.62b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-instrumentation", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-semantic-conventions", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "opentelemetry-util-http", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "wrapt", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/3b/3feb8c0ff2ce154a1633580269ba89f0f6a247a930761c6ef3419dc3a534/opentelemetry_instrumentation_aiohttp_client-0.62b1.tar.gz", hash = "sha256:602c52358fdf56841ded98025593298f93de5c98fc8ab7799f5282e227bd9487", size = 19313, upload-time = "2026-04-24T13:22:33.996Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/77/4518a02b266c9f97083c93b38865956cc99029e97ecad1e544bbabee9452/opentelemetry_instrumentation_aiohttp_client-0.62b1-py3-none-any.whl", hash = "sha256:e0fbf5489e4c5e08928de25ae9efcceb6f94c2a8e9f5e9529e3434a50aacfd01", size = 14533, upload-time = "2026-04-24T13:21:34.309Z" }, +] + [[package]] name = "opentelemetry-proto" version = "1.41.1" @@ -4289,16 +4992,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/22/41fb05f1dc5fda2c468e05a41814c20859016c85117b66c8a257cae814f6/opentelemetry_semantic_conventions_ai-0.5.1-py3-none-any.whl", hash = "sha256:25aeb22bd261543b4898a73824026d96770e5351209c7d07a0b1314762b1f6e4", size = 11250, upload-time = "2026-03-26T14:20:37.108Z" }, ] +[[package]] +name = "opentelemetry-util-http" +version = "0.62b1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/1b/aa71b63e18d30a8384036b9937f40f7618f8030a7aa213155fb54f6f2b47/opentelemetry_util_http-0.62b1.tar.gz", hash = "sha256:adf6facbb89aef8f8bc566e2f04624942ba08a7b678b3479a91051a8f4dc70a3", size = 11393, upload-time = "2026-04-24T13:23:12.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/a9d9d32161c1ced61346267db4c9702da54f81ec5dc88214bc65c23f4e9d/opentelemetry_util_http-0.62b1-py3-none-any.whl", hash = "sha256:c57e8a6c19fc422c288e6074e882f506f85030b69b7376182f74f9257b9261f0", size = 9295, upload-time = "2026-04-24T13:22:28.078Z" }, +] + [[package]] name = "orjson" version = "3.11.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", size = 5599163, upload-time = "2026-05-06T15:11:08.309Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/32/33/93fcc25907235c344ae73122f8a4e01d2d393ef062b4af7d2e2487a32c37/orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021", size = 228458, upload-time = "2026-05-06T15:10:20.079Z" }, + { url = "https://files.pythonhosted.org/packages/8f/27/b1e6dadb3c080313c03fdd8067b85e6a0460c7d8d6a1c3984ef77b904e4d/orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c", size = 128368, upload-time = "2026-05-06T15:10:21.549Z" }, { url = "https://files.pythonhosted.org/packages/21/0f/c9ede0bf052f6b4051e64a7d4fa91b725cccf8321a6a786e86eb03519f00/orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81", size = 132070, upload-time = "2026-05-06T15:10:23.371Z" }, + { url = "https://files.pythonhosted.org/packages/fd/26/d398e28048dc18205bbe812f2c88cb9b40313db2470778e25964796458fe/orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a", size = 127892, upload-time = "2026-05-06T15:10:24.714Z" }, + { url = "https://files.pythonhosted.org/packages/66/60/52b0054c4c700d5aa7fc5b7ca96917400d8f061307778578e67a10e25852/orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10", size = 135217, upload-time = "2026-05-06T15:10:26.084Z" }, + { url = "https://files.pythonhosted.org/packages/d5/97/1e3dc2b2a28b7b2528f403d2fc1d79ec5f39af3bc143ab65d3ec26426385/orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362", size = 145980, upload-time = "2026-05-06T15:10:28.062Z" }, + { url = "https://files.pythonhosted.org/packages/fc/39/31fbfe7850f2de32dee7e7e5c09f26d403ab01e440ac96001c6b01ad3c99/orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97", size = 132738, upload-time = "2026-05-06T15:10:29.727Z" }, { url = "https://files.pythonhosted.org/packages/a1/08/dca0082dd2a194acb93e5457e73455388e2e2ca464a2672449a9ddbb679d/orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218", size = 134033, upload-time = "2026-05-06T15:10:31.152Z" }, { url = "https://files.pythonhosted.org/packages/11/d4/5bdb0626801230139987385554c5d4c42255218ac906525bf4347f22cd95/orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9", size = 141492, upload-time = "2026-05-06T15:10:32.641Z" }, + { url = "https://files.pythonhosted.org/packages/fa/88/a21fb53b3ede6703aede6dce4710ed4111e5b201cfa6bbff5e544f9d47d7/orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677", size = 415087, upload-time = "2026-05-06T15:10:34.438Z" }, + { url = "https://files.pythonhosted.org/packages/3d/57/1b30daf70f0d8180e9a73cefbfbdd99e4bf19eb020466502b01fba7e0e50/orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4", size = 148031, upload-time = "2026-05-06T15:10:36.358Z" }, { url = "https://files.pythonhosted.org/packages/04/83/45fbb6d962e260807f99441db9613cee868ceda4baceda59b3720a563f97/orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0", size = 136915, upload-time = "2026-05-06T15:10:38.013Z" }, + { url = "https://files.pythonhosted.org/packages/5f/cc/2d10025f9056d376e4127ec05a5808b218d46f035fdc08178a5411b34250/orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32", size = 131613, upload-time = "2026-05-06T15:10:39.569Z" }, + { url = "https://files.pythonhosted.org/packages/67/bd/2775ff28bfe883b9aa1ff348300542eb2ef1ee18d8ae0e3a49846817a865/orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979", size = 127086, upload-time = "2026-05-06T15:10:41.262Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/d26799e580939e32a7da9a39531bc9e58e15ca32ffaa6a8cb3e9bb0d22cd/orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254", size = 126696, upload-time = "2026-05-06T15:10:42.651Z" }, ] [[package]] @@ -4328,8 +5051,14 @@ version = "0.2.14" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6a/04/4a0812eb27c086cfd2e66e7ec9150f33e105912a9b7f8b335e3479f03a06/outlines_core-0.2.14.tar.gz", hash = "sha256:64808deed1591ca3029ff64346ceb974cd5d780c916ea82504951fe83523039e", size = 191539, upload-time = "2026-01-09T15:59:10.016Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/13/9d/e6c81c975c123f0639d5f6909c987e510d43e07c2e1e6495b21639c4dec6/outlines_core-0.2.14-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8b3e8d668188282a1f7666732bb8a01958ab134db35bb792e7442a40e55ff1e7", size = 2049297, upload-time = "2026-01-09T15:58:39.184Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d1/5ce55ef724aed0915edc877b6dd610d39b3169e4341154bb53daa022065a/outlines_core-0.2.14-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:66e695b375b180725fb534d9adf298531c152ec3d881e3b9e01c82b5dd269f52", size = 2200944, upload-time = "2026-01-09T15:58:40.257Z" }, + { url = "https://files.pythonhosted.org/packages/32/e3/60ad781251eedcf1496317ecd58eb2e4488717ba63b10494ab49dfd05e5d/outlines_core-0.2.14-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:6bd166d3b07acef2f60d4ede44592a26d3f7d8712876bfc8e22150045def5857", size = 2049607, upload-time = "2026-01-09T15:58:41.635Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2d/662d6a76face5b4b3481f888900d00856c37aa2927341a023866457da212/outlines_core-0.2.14-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:9d45462d7548aa0e17176a691ae73447f3e6bed9658a0cd96fe72eadf7474475", size = 2197755, upload-time = "2026-01-09T15:58:42.861Z" }, { url = "https://files.pythonhosted.org/packages/c1/9a/4b62903de006d991b58674ff033c1b6fb92be5767360376fc961f6771bdb/outlines_core-0.2.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6453e23f01d98ec48e3a4141d7112792ce77001dfb28d91d6fd89f47009f91ef", size = 2341051, upload-time = "2026-01-09T15:58:44.415Z" }, { url = "https://files.pythonhosted.org/packages/50/36/1532f7d9ab16c676812d94528e89964aa0d15f12adcb285e6ed86f86f2fe/outlines_core-0.2.14-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7deef6df74cb247f2a3a62f03438ba967456504b0555ec7029f8db834e054448", size = 2236778, upload-time = "2026-01-09T15:58:45.437Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5a/dfd94f15f4c04e691e7fdf30cf8b9b22bf2cbc426b3ef270af3e200596d5/outlines_core-0.2.14-cp313-cp313-win32.whl", hash = "sha256:bb008c7ecc034bcfda0ddc10a4d1f2181a4b61ec1643ee56183dd6fa64139c9d", size = 1842727, upload-time = "2026-01-09T15:58:46.723Z" }, + { url = "https://files.pythonhosted.org/packages/34/35/e24ab5d2116812464380587435297d8ece2f0218c2ba8afc9f541e3a6911/outlines_core-0.2.14-cp313-cp313-win_amd64.whl", hash = "sha256:eb27e92204b296a063ac58f361153be4e78c8103a96e0b1c085b22d4fc3534cf", size = 2137108, upload-time = "2026-01-09T15:58:47.784Z" }, ] [[package]] @@ -4353,10 +5082,15 @@ dependencies = [ ] 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/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" }, @@ -4432,18 +5166,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" }, { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" }, { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" }, + { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" }, + { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" }, { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" }, { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" }, { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" }, { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" }, { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" }, { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" }, + { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" }, + { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" }, + { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" }, + { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" }, { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" }, { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" }, { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" }, { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" }, { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" }, { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" }, + { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, ] [[package]] @@ -4538,7 +5282,7 @@ version = "8.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "prometheus-client", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "starlette", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/e9/2065686d1dfa62296fdc158b6e8fd25b0cb3dca09b0632cabeb5ae81fe4d/prometheus_fastapi_instrumentator-8.0.2.tar.gz", hash = "sha256:3c252e748151768a7aefd66824a04a870144f71de48a67aed211749a9ca2a548", size = 21342, upload-time = "2026-06-23T09:39:31.611Z" } wheels = [ @@ -4563,14 +5307,40 @@ version = "0.5.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/09/f049e45385503fe67db75a6b6186a7b9f0c3930366dc960522c312a825b1/propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a", size = 94457, upload-time = "2026-05-08T21:00:36.355Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/83d1d05655baf63113731bd5a1008435e14f8d1e5a06cbe4ec5b23ad7a31/propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117", size = 53835, upload-time = "2026-05-08T21:00:38.072Z" }, + { url = "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098", size = 54545, upload-time = "2026-05-08T21:00:39.319Z" }, { url = "https://files.pythonhosted.org/packages/a9/19/7fa086f5764c59ec8a8e157cd93aa8497acc00aba9dcdec56bfffb32602d/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4", size = 59886, upload-time = "2026-05-08T21:00:40.621Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e4/5d7663dc8235956c8f5281698a3af1d351d8820341ddd890f59d9a9127f2/propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e", size = 63261, upload-time = "2026-05-08T21:00:41.775Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4a/15a03adee24d6350da4292caeac44c34c033d2afe5e87eb370f38854560f/propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7", size = 64184, upload-time = "2026-05-08T21:00:43.018Z" }, { url = "https://files.pythonhosted.org/packages/8b/c6/979176efdaa3d239e36d503d5af63a0a773b36662ed8f52e5b6a6d9fd40e/propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d", size = 61534, upload-time = "2026-05-08T21:00:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/c8/22/63e8cd1bae4c2d2be6493b6b7d10566ddafad88137cfbc99964a1119853c/propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a", size = 61500, upload-time = "2026-05-08T21:00:45.796Z" }, { url = "https://files.pythonhosted.org/packages/60/5a/28e5d9acbac1cc9ccb67045e8c1b943aa8d79fdf39c93bd73cacd68008ea/propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2", size = 59994, upload-time = "2026-05-08T21:00:47.093Z" }, + { url = "https://files.pythonhosted.org/packages/f3/40/db650677f554a95b9c01a7c9d93d629e93a15562f5deb4573c9ee136fed2/propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa", size = 56884, upload-time = "2026-05-08T21:00:48.376Z" }, + { url = "https://files.pythonhosted.org/packages/80/45/70b39b89516ff8b96bf732fa6fded8cef20f293cb1508690101c3c07ec51/propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853", size = 63464, upload-time = "2026-05-08T21:00:49.954Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e2/fa59d3a89eac5534293124af4f1d0d0ada091ce4a0ab4610ce03fd2bdd8d/propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a", size = 61588, upload-time = "2026-05-08T21:00:51.281Z" }, + { url = "https://files.pythonhosted.org/packages/0b/97/efb547a55c4bc7381cfb202d6a2239ac621045277bc1ea5dfd3a7f0516c0/propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704", size = 64667, upload-time = "2026-05-08T21:00:52.602Z" }, { url = "https://files.pythonhosted.org/packages/92/56/f5c7d9b4b7595d5127da38974d791b2153f3d1eae6c674af3583ace92ad3/propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4", size = 62463, upload-time = "2026-05-08T21:00:54.303Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3b/484a3a65fc9f9f60c41dcd17b428bace5389544e2c680994534a20755066/propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d", size = 38621, upload-time = "2026-05-08T21:00:55.808Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fd/3f0f10dba4dabad3bf53102be007abf55481067952bde0fdddff439e7c61/propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757", size = 41649, upload-time = "2026-05-08T21:00:57.061Z" }, + { url = "https://files.pythonhosted.org/packages/90/ec/6ce619cc32bb500a482f811f9cd509368b4e58e638d13f2c68f370d6b475/propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f", size = 37636, upload-time = "2026-05-08T21:00:58.646Z" }, + { url = "https://files.pythonhosted.org/packages/1b/82/c1d268bbbf2ef981c5bf0fbbe746db617c66e3bcefe431a1aa8943fbe23a/propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d", size = 98872, upload-time = "2026-05-08T21:00:59.889Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d4/52c871e73e864e6b34c0e2d58ac1ec5ccd149497ddc7ad2137ae98323a35/propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa", size = 56257, upload-time = "2026-05-08T21:01:01.195Z" }, + { url = "https://files.pythonhosted.org/packages/67/f0/9b90ca2a210b3d09bcfcd96ecd0f55545c091535abce2a45de2775cfd357/propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94", size = 56696, upload-time = "2026-05-08T21:01:02.941Z" }, { url = "https://files.pythonhosted.org/packages/9d/0e/6e9d4ba07c8e56e21ddec1e75f12148142b21ca83a51871babce095334f4/propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164", size = 62378, upload-time = "2026-05-08T21:01:04.475Z" }, + { url = "https://files.pythonhosted.org/packages/65/19/c10badaa463dde8a27ce884f8ee2ec37e6035b7c9f5ff0c8f74f06f08dac/propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f", size = 65283, upload-time = "2026-05-08T21:01:05.959Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b6/93bea99ca80e19cef6512a8580e5b7857bbe09422d9daa7fd4ef5723306c/propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c", size = 66616, upload-time = "2026-05-08T21:01:07.228Z" }, { url = "https://files.pythonhosted.org/packages/83/e4/5c7462e50625f051f37fb38b8224f7639f667184bbd34424ec83819bb1b7/propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc", size = 63773, upload-time = "2026-05-08T21:01:08.514Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b6/99238894047b13c823be25027e736626cd414a52a5e30d2c3347c2733529/propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f", size = 63664, upload-time = "2026-05-08T21:01:09.874Z" }, { url = "https://files.pythonhosted.org/packages/85/1e/a3a1a63116a2b8edb415a8bb9a6f0c34bd03830b1e18e8ce2904e1dc1cf4/propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb", size = 62643, upload-time = "2026-05-08T21:01:11.132Z" }, + { url = "https://files.pythonhosted.org/packages/e4/03/893cf147de2fc6543c5eaa07ad833170e7e2a2385725bbebe8c0503723bb/propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751", size = 59595, upload-time = "2026-05-08T21:01:12.387Z" }, + { url = "https://files.pythonhosted.org/packages/86/3b/04c1a2e12c57766568ba75ba72b3bf2042818d4c1425fab6fc07155c7cff/propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836", size = 65711, upload-time = "2026-05-08T21:01:13.676Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/80f8d0099f8d6bacc4de1624c85672681c8cd1149ca2da0e38fd120b817f/propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f", size = 64247, upload-time = "2026-05-08T21:01:14.936Z" }, + { url = "https://files.pythonhosted.org/packages/f3/1a/8b08f3a5f1037e9e370c55883ceeeee0f6dd0416fb2d2d67b8bfc91f2a79/propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55", size = 67102, upload-time = "2026-05-08T21:01:16.281Z" }, { url = "https://files.pythonhosted.org/packages/34/68/8bdb7bb7756d76e005490649d10e4a8369e610c74d619f71e1aedf889e9c/propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568", size = 64964, upload-time = "2026-05-08T21:01:17.57Z" }, + { url = "https://files.pythonhosted.org/packages/0a/aa/50fb0b5d3968b61a510926ff8b8465f1d6e976b3ab74496d7a4b9fc42515/propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191", size = 42546, upload-time = "2026-05-08T21:01:18.946Z" }, + { url = "https://files.pythonhosted.org/packages/ae/4c/0ddbae64321bd4a95bcbfc19307238016b5b1fee645c84626c8d539e5b74/propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7", size = 46330, upload-time = "2026-05-08T21:01:20.162Z" }, + { url = "https://files.pythonhosted.org/packages/00/d9/9cddc8efb78d8af264c5ec9f6d10b62f57c515feda8d321595f56010fb23/propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96", size = 40521, upload-time = "2026-05-08T21:01:21.399Z" }, { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, ] @@ -4592,7 +5362,11 @@ version = "6.33.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, ] @@ -4603,12 +5377,20 @@ 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]] @@ -4653,8 +5435,13 @@ version = "0.4.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/93/d8/5b71371f50cf153b1307e5a11ac8a4ce4d85651dae946bd7e9a064146545/py_spy-0.4.2.tar.gz", hash = "sha256:90e600b27bb6bb40479637baca5a5b4bc2ba3395c93d889e672315d93042c4ae", size = 286374, upload-time = "2026-04-24T22:08:54.906Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/21/ec030145a0c7992bd4b9eafb2f06f56358b3a5339eab4a16534baf3c69aa/py_spy-0.4.2-py2.py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:1ccf688393105111684435f035bc14ec3f22117dd2b85b2414612cf27a22755a", size = 3743992, upload-time = "2026-04-24T22:08:45.438Z" }, + { url = "https://files.pythonhosted.org/packages/50/80/de5fd27243c2be03692ecd317bf0dbe24b4c6f78f689ce111e7277a7cb09/py_spy-0.4.2-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:a0e6f6810ccf0fc5e64e85e0182a5b626c4496eec01b14fb8755154b363a4831", size = 1859057, upload-time = "2026-04-24T22:08:46.946Z" }, { url = "https://files.pythonhosted.org/packages/89/23/3eb4c23c684ebd667674ce1d076ae855e0621d1d9bd5e052aa3f7982f757/py_spy-0.4.2-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:142887e984a4e541071c99a4401ff8c3770f255d329dbd0f64e8c1dd51882cce", size = 2828136, upload-time = "2026-04-24T22:08:48.519Z" }, + { url = "https://files.pythonhosted.org/packages/ca/01/6314152cf9ad3310ebacbf2c47b5ed858086530f8e12b1a665725ca5e0f4/py_spy-0.4.2-py2.py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1c6d9b0e2379ead5bf792df43f4cf36153aa79e6dda4fb8ac7740cf8017110", size = 2857707, upload-time = "2026-04-24T22:08:49.677Z" }, + { url = "https://files.pythonhosted.org/packages/cc/1f/0960a129d504728d28a51dbd5a04ce94031eb75bac676341da7aefdd8232/py_spy-0.4.2-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24720573f95230653b457671a1dcc3c5a381fcf4e92677761e328a430ad251b2", size = 2301852, upload-time = "2026-04-24T22:08:51.152Z" }, { url = "https://files.pythonhosted.org/packages/f9/34/dd7d3c763a00b7b965e25a5eab0acd1a345dbaf0f45fffe595278873a1c0/py_spy-0.4.2-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:aeb0323409199c785f730645e9f4bb7a7b9ca2c481f2c331a55642b5d13fa52f", size = 2936518, upload-time = "2026-04-24T22:08:52.264Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ed/1409cdb557e558a6c98003ab12fdd4284699e158c167c187cb0f124eea4c/py_spy-0.4.2-py2.py3-none-win_amd64.whl", hash = "sha256:8b06a353c177677e4e1701b288d8c58e2f8d4208ee81a8048d9f72ba800918f8", size = 1894002, upload-time = "2026-04-24T22:08:53.811Z" }, ] [[package]] @@ -4663,14 +5450,20 @@ 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/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]] @@ -4700,17 +5493,49 @@ version = "1.4.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/aa/b8/4ed5c7ad5ec15b08d35cc79ace6145d5c1ae426e46435f4987379439dfea/pybase64-1.4.3.tar.gz", hash = "sha256:c2ed274c9e0ba9c8f9c4083cfe265e66dd679126cd9c2027965d807352f3f053", size = 137272, upload-time = "2025-12-06T13:27:04.013Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/50/b7170cb2c631944388fe2519507fe3835a4054a6a12a43f43781dae82be1/pybase64-1.4.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:ea4b785b0607d11950b66ce7c328f452614aefc9c6d3c9c28bae795dc7f072e1", size = 33901, upload-time = "2025-12-06T13:23:40.951Z" }, + { url = "https://files.pythonhosted.org/packages/48/8b/69f50578e49c25e0a26e3ee72c39884ff56363344b79fc3967f5af420ed6/pybase64-1.4.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:6a10b6330188c3026a8b9c10e6b9b3f2e445779cf16a4c453d51a072241c65a2", size = 40807, upload-time = "2025-12-06T13:23:42.006Z" }, { url = "https://files.pythonhosted.org/packages/5c/8d/20b68f11adfc4c22230e034b65c71392e3e338b413bf713c8945bd2ccfb3/pybase64-1.4.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:27fdff227a0c0e182e0ba37a99109645188978b920dfb20d8b9c17eeee370d0d", size = 30932, upload-time = "2025-12-06T13:23:43.348Z" }, { url = "https://files.pythonhosted.org/packages/f7/79/b1b550ac6bff51a4880bf6e089008b2e1ca16f2c98db5e039a08ac3ad157/pybase64-1.4.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2a8204f1fdfec5aa4184249b51296c0de95445869920c88123978304aad42df1", size = 31394, upload-time = "2025-12-06T13:23:44.317Z" }, { url = "https://files.pythonhosted.org/packages/82/70/b5d7c5932bf64ee1ec5da859fbac981930b6a55d432a603986c7f509c838/pybase64-1.4.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:874fc2a3777de6baf6aa921a7aa73b3be98295794bea31bd80568a963be30767", size = 38078, upload-time = "2025-12-06T13:23:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/56/fe/e66fe373bce717c6858427670736d54297938dad61c5907517ab4106bd90/pybase64-1.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2dc64a94a9d936b8e3449c66afabbaa521d3cc1a563d6bbaaa6ffa4535222e4b", size = 38158, upload-time = "2025-12-06T13:23:46.872Z" }, + { url = "https://files.pythonhosted.org/packages/80/a9/b806ed1dcc7aed2ea3dd4952286319e6f3a8b48615c8118f453948e01999/pybase64-1.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e48f86de1c145116ccf369a6e11720ce696c2ec02d285f440dfb57ceaa0a6cb4", size = 31672, upload-time = "2025-12-06T13:23:47.88Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c9/24b3b905cf75e23a9a4deaf203b35ffcb9f473ac0e6d8257f91a05dfce62/pybase64-1.4.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:1d45c8fe8fe82b65c36b227bb4a2cf623d9ada16bed602ce2d3e18c35285b72a", size = 68244, upload-time = "2025-12-06T13:23:49.026Z" }, { url = "https://files.pythonhosted.org/packages/f8/cd/d15b0c3e25e5859fab0416dc5b96d34d6bd2603c1c96a07bb2202b68ab92/pybase64-1.4.3-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ad70c26ba091d8f5167e9d4e1e86a0483a5414805cdb598a813db635bd3be8b8", size = 71620, upload-time = "2025-12-06T13:23:50.081Z" }, { url = "https://files.pythonhosted.org/packages/0d/31/4ca953cc3dcde2b3711d6bfd70a6f4ad2ca95a483c9698076ba605f1520f/pybase64-1.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e98310b7c43145221e7194ac9fa7fffc84763c87bfc5e2f59f9f92363475bdc1", size = 59930, upload-time = "2025-12-06T13:23:51.68Z" }, + { url = "https://files.pythonhosted.org/packages/60/55/e7f7bdcd0fd66e61dda08db158ffda5c89a306bbdaaf5a062fbe4e48f4a1/pybase64-1.4.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:398685a76034e91485a28aeebcb49e64cd663212fd697b2497ac6dfc1df5e671", size = 56425, upload-time = "2025-12-06T13:23:52.732Z" }, + { url = "https://files.pythonhosted.org/packages/cb/65/b592c7f921e51ca1aca3af5b0d201a98666d0a36b930ebb67e7c2ed27395/pybase64-1.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7e46400a6461187ccb52ed75b0045d937529e801a53a9cd770b350509f9e4d50", size = 59327, upload-time = "2025-12-06T13:23:53.856Z" }, + { url = "https://files.pythonhosted.org/packages/23/95/1613d2fb82dbb1548595ad4179f04e9a8451bfa18635efce18b631eabe3f/pybase64-1.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1b62b9f2f291d94f5e0b76ab499790b7dcc78a009d4ceea0b0428770267484b6", size = 60294, upload-time = "2025-12-06T13:23:54.937Z" }, + { url = "https://files.pythonhosted.org/packages/9d/73/40431f37f7d1b3eab4673e7946ff1e8f5d6bd425ec257e834dae8a6fc7b0/pybase64-1.4.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:f30ceb5fa4327809dede614be586efcbc55404406d71e1f902a6fdcf322b93b2", size = 54858, upload-time = "2025-12-06T13:23:56.031Z" }, { url = "https://files.pythonhosted.org/packages/a7/84/f6368bcaf9f743732e002a9858646fd7a54f428490d427dd6847c5cfe89e/pybase64-1.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0d5f18ed53dfa1d4cf8b39ee542fdda8e66d365940e11f1710989b3cf4a2ed66", size = 58629, upload-time = "2025-12-06T13:23:57.12Z" }, + { url = "https://files.pythonhosted.org/packages/43/75/359532f9adb49c6b546cafc65c46ed75e2ccc220d514ba81c686fbd83965/pybase64-1.4.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:119d31aa4b58b85a8ebd12b63c07681a138c08dfc2fe5383459d42238665d3eb", size = 52448, upload-time = "2025-12-06T13:23:58.298Z" }, + { url = "https://files.pythonhosted.org/packages/92/6c/ade2ba244c3f33ed920a7ed572ad772eb0b5f14480b72d629d0c9e739a40/pybase64-1.4.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3cf0218b0e2f7988cf7d738a73b6a1d14f3be6ce249d7c0f606e768366df2cce", size = 68841, upload-time = "2025-12-06T13:23:59.886Z" }, + { url = "https://files.pythonhosted.org/packages/a0/51/b345139cd236be382f2d4d4453c21ee6299e14d2f759b668e23080f8663f/pybase64-1.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:12f4ee5e988bc5c0c1106b0d8fc37fb0508f12dab76bac1b098cb500d148da9d", size = 57910, upload-time = "2025-12-06T13:24:00.994Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b8/9f84bdc4f1c4f0052489396403c04be2f9266a66b70c776001eaf0d78c1f/pybase64-1.4.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:937826bc7b6b95b594a45180e81dd4d99bd4dd4814a443170e399163f7ff3fb6", size = 54335, upload-time = "2025-12-06T13:24:02.046Z" }, + { url = "https://files.pythonhosted.org/packages/d0/c7/be63b617d284de46578a366da77ede39c8f8e815ed0d82c7c2acca560fab/pybase64-1.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:88995d1460971ef80b13e3e007afbe4b27c62db0508bc7250a2ab0a0b4b91362", size = 56486, upload-time = "2025-12-06T13:24:03.141Z" }, { url = "https://files.pythonhosted.org/packages/5e/96/f252c8f9abd6ded3ef1ccd3cdbb8393a33798007f761b23df8de1a2480e6/pybase64-1.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:72326fe163385ed3e1e806dd579d47fde5d8a59e51297a60fc4e6cbc1b4fc4ed", size = 70978, upload-time = "2025-12-06T13:24:04.221Z" }, + { url = "https://files.pythonhosted.org/packages/af/51/0f5714af7aeef96e30f968e4371d75ad60558aaed3579d7c6c8f1c43c18a/pybase64-1.4.3-cp313-cp313-win32.whl", hash = "sha256:b1623730c7892cf5ed0d6355e375416be6ef8d53ab9b284f50890443175c0ac3", size = 33684, upload-time = "2025-12-06T13:24:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ad/0cea830a654eb08563fb8214150ef57546ece1cc421c09035f0e6b0b5ea9/pybase64-1.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:8369887590f1646a5182ca2fb29252509da7ae31d4923dbb55d3e09da8cc4749", size = 35832, upload-time = "2025-12-06T13:24:06.35Z" }, + { url = "https://files.pythonhosted.org/packages/b4/0d/eec2a8214989c751bc7b4cad1860eb2c6abf466e76b77508c0f488c96a37/pybase64-1.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:860b86bca71e5f0237e2ab8b2d9c4c56681f3513b1bf3e2117290c1963488390", size = 31175, upload-time = "2025-12-06T13:24:07.419Z" }, + { url = "https://files.pythonhosted.org/packages/db/c9/e23463c1a2913686803ef76b1a5ae7e6fac868249a66e48253d17ad7232c/pybase64-1.4.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eb51db4a9c93215135dccd1895dca078e8785c357fabd983c9f9a769f08989a9", size = 38497, upload-time = "2025-12-06T13:24:08.873Z" }, + { url = "https://files.pythonhosted.org/packages/71/83/343f446b4b7a7579bf6937d2d013d82f1a63057cf05558e391ab6039d7db/pybase64-1.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a03ef3f529d85fd46b89971dfb00c634d53598d20ad8908fb7482955c710329d", size = 32076, upload-time = "2025-12-06T13:24:09.975Z" }, + { url = "https://files.pythonhosted.org/packages/46/fc/cb64964c3b29b432f54d1bce5e7691d693e33bbf780555151969ffd95178/pybase64-1.4.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2e745f2ce760c6cf04d8a72198ef892015ddb89f6ceba489e383518ecbdb13ab", size = 72317, upload-time = "2025-12-06T13:24:11.129Z" }, { url = "https://files.pythonhosted.org/packages/0a/b7/fab2240da6f4e1ad46f71fa56ec577613cf5df9dce2d5b4cfaa4edd0e365/pybase64-1.4.3-cp313-cp313t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fac217cd9de8581a854b0ac734c50fd1fa4b8d912396c1fc2fce7c230efe3a7", size = 75534, upload-time = "2025-12-06T13:24:12.433Z" }, { url = "https://files.pythonhosted.org/packages/91/3b/3e2f2b6e68e3d83ddb9fa799f3548fb7449765daec9bbd005a9fbe296d7f/pybase64-1.4.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:da1ee8fa04b283873de2d6e8fa5653e827f55b86bdf1a929c5367aaeb8d26f8a", size = 65399, upload-time = "2025-12-06T13:24:13.928Z" }, + { url = "https://files.pythonhosted.org/packages/6b/08/476ac5914c3b32e0274a2524fc74f01cbf4f4af4513d054e41574eb018f6/pybase64-1.4.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:b0bf8e884ee822ca7b1448eeb97fa131628fe0ff42f60cae9962789bd562727f", size = 60487, upload-time = "2025-12-06T13:24:15.177Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b8/618a92915330cc9cba7880299b546a1d9dab1a21fd6c0292ee44a4fe608c/pybase64-1.4.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1bf749300382a6fd1f4f255b183146ef58f8e9cb2f44a077b3a9200dfb473a77", size = 63959, upload-time = "2025-12-06T13:24:16.854Z" }, + { url = "https://files.pythonhosted.org/packages/a5/52/af9d8d051652c3051862c442ec3861259c5cdb3fc69774bc701470bd2a59/pybase64-1.4.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:153a0e42329b92337664cfc356f2065248e6c9a1bd651bbcd6dcaf15145d3f06", size = 64874, upload-time = "2025-12-06T13:24:18.328Z" }, + { url = "https://files.pythonhosted.org/packages/e4/51/5381a7adf1f381bd184d33203692d3c57cf8ae9f250f380c3fecbdbe554b/pybase64-1.4.3-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:86ee56ac7f2184ca10217ed1c655c1a060273e233e692e9086da29d1ae1768db", size = 58572, upload-time = "2025-12-06T13:24:19.417Z" }, { url = "https://files.pythonhosted.org/packages/e0/f0/578ee4ffce5818017de4fdf544e066c225bc435e73eb4793cde28a689d0b/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0e71a4db76726bf830b47477e7d830a75c01b2e9b01842e787a0836b0ba741e3", size = 63636, upload-time = "2025-12-06T13:24:20.497Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ad/8ae94814bf20159ea06310b742433e53d5820aa564c9fdf65bf2d79f8799/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2ba7799ec88540acd9861b10551d24656ca3c2888ecf4dba2ee0a71544a8923f", size = 56193, upload-time = "2025-12-06T13:24:21.559Z" }, + { url = "https://files.pythonhosted.org/packages/d1/31/6438cfcc3d3f0fa84d229fa125c243d5094e72628e525dfefadf3bcc6761/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2860299e4c74315f5951f0cf3e72ba0f201c3356c8a68f95a3ab4e620baf44e9", size = 72655, upload-time = "2025-12-06T13:24:22.673Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0d/2bbc9e9c3fc12ba8a6e261482f03a544aca524f92eae0b4908c0a10ba481/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:bb06015db9151f0c66c10aae8e3603adab6b6cd7d1f7335a858161d92fc29618", size = 62471, upload-time = "2025-12-06T13:24:23.8Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0b/34d491e7f49c1dbdb322ea8da6adecda7c7cd70b6644557c6e4ca5c6f7c7/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:242512a070817272865d37c8909059f43003b81da31f616bb0c391ceadffe067", size = 58119, upload-time = "2025-12-06T13:24:24.994Z" }, + { url = "https://files.pythonhosted.org/packages/ce/17/c21d0cde2a6c766923ae388fc1f78291e1564b0d38c814b5ea8a0e5e081c/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5d8277554a12d3e3eed6180ebda62786bf9fc8d7bb1ee00244258f4a87ca8d20", size = 60791, upload-time = "2025-12-06T13:24:26.046Z" }, { url = "https://files.pythonhosted.org/packages/92/b2/eaa67038916a48de12b16f4c384bcc1b84b7ec731b23613cb05f27673294/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f40b7ddd698fc1e13a4b64fbe405e4e0e1279e8197e37050e24154655f5f7c4e", size = 74701, upload-time = "2025-12-06T13:24:27.466Z" }, + { url = "https://files.pythonhosted.org/packages/42/10/abb7757c330bb869ebb95dab0c57edf5961ffbd6c095c8209cbbf75d117d/pybase64-1.4.3-cp313-cp313t-win32.whl", hash = "sha256:46d75c9387f354c5172582a9eaae153b53a53afeb9c19fcf764ea7038be3bd8b", size = 33965, upload-time = "2025-12-06T13:24:28.548Z" }, + { url = "https://files.pythonhosted.org/packages/63/a0/2d4e5a59188e9e6aed0903d580541aaea72dcbbab7bf50fb8b83b490b6c3/pybase64-1.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:d7344625591d281bec54e85cbfdab9e970f6219cac1570f2aa140b8c942ccb81", size = 36207, upload-time = "2025-12-06T13:24:29.646Z" }, + { url = "https://files.pythonhosted.org/packages/1f/05/95b902e8f567b4d4b41df768ccc438af618f8d111e54deaf57d2df46bd76/pybase64-1.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:28a3c60c55138e0028313f2eccd321fec3c4a0be75e57a8d3eb883730b1b0880", size = 31505, upload-time = "2025-12-06T13:24:30.687Z" }, ] [[package]] @@ -4746,14 +5571,28 @@ version = "3.23.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, ] [[package]] @@ -4785,10 +5624,21 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, + { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, + { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, ] [[package]] @@ -4914,8 +5764,14 @@ version = "0.24.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/26/c3/17be94de732d01d86a671eb1e93608000a0594e60d05a14c5d9f13dbe21d/pyrefly-0.24.2.tar.gz", hash = "sha256:671b9933c2a3f646983de68bc0422736f7ce364c4f645f742559423b0b9b5150", size = 1129442, upload-time = "2025-07-15T02:40:19.25Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/cd/07862f0afd79e215617494495510d06cb7cc5907f5f32594498e7bb64f7e/pyrefly-0.24.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7e6bd1b88ec53b3f1ce2ece844016d7e7f0848a77022857a7fa6674a49abcc13", size = 6049599, upload-time = "2025-07-15T02:40:03.363Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ce/680ce3c12a9d8cf0312207d1eee31947e5ceae169680fe2e341718f299be/pyrefly-0.24.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:83aa9013f2299dfc8ce11adec30a63be71528484c45e603375efe7496cb0538e", size = 5634851, upload-time = "2025-07-15T02:40:05.742Z" }, { url = "https://files.pythonhosted.org/packages/0f/12/3846ceefaeccb6209b4bcb3518143039effbe7f16f864377949b78952814/pyrefly-0.24.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bf1689032b78f8f653244cd323ee1e06a0efb6192c4d7a415d1e85aedd37905", size = 5852019, upload-time = "2025-07-15T02:40:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/a0/a3/cab8503091f244aa243995cb8745842198d71eb71225abe9ba8a1de78024/pyrefly-0.24.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8404b804a5a1bc4a54cc8e58bceacdf49d7221531843c068547241d8f476af24", size = 6546257, upload-time = "2025-07-15T02:40:09.729Z" }, { url = "https://files.pythonhosted.org/packages/e0/06/b2881239f4a22c800003feaa3e653d6f635ea8979db506545e3c43bbf606/pyrefly-0.24.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d09f166a46e43655ea812611887ca16a0c54386296f4c9333f3f5fc7236709", size = 6296266, upload-time = "2025-07-15T02:40:11.667Z" }, + { url = "https://files.pythonhosted.org/packages/66/39/c414c1a30c24badb5153dd2d1ddb974d5b5662f80be9f1fed626fcfe6479/pyrefly-0.24.2-py3-none-win32.whl", hash = "sha256:6c602df48dcfa3240f9076c7d1e9cf9dc2d94c90ee5b4c6745f3734125a2cf3a", size = 5833755, upload-time = "2025-07-15T02:40:13.539Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2b/36d211dd03b86cb6216968f64081437837507debe30f58834a97091eda83/pyrefly-0.24.2-py3-none-win_amd64.whl", hash = "sha256:9ed4690716eb47077082d4e99624e0a1165b9ac93300c8d823f42cae12ec1ef4", size = 6207616, upload-time = "2025-07-15T02:40:15.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/9a/d51db168fe6bdae00b813582287d251e116666f07cb388b62d1715808891/pyrefly-0.24.2-py3-none-win_arm64.whl", hash = "sha256:96ba49c02f374d716b8674409aa653093dad5263cf4e429a1d5ec603064db715", size = 5867507, upload-time = "2025-07-15T02:40:16.793Z" }, ] [[package]] @@ -5052,6 +5908,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] +[[package]] +name = "python-engineio" +version = "4.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "simple-websocket", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/a0/f75491f942184d9960b15e763270f765fe9f239745ca5f9e16289011aed4/python_engineio-4.13.3.tar.gz", hash = "sha256:572b7783e341fed21edbc7cea297ccd378dad79265fdde96aa4664420a7c06c9", size = 79734, upload-time = "2026-06-20T22:53:52.197Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/96/82f6328e410515fab21d5602ba35b9377a47b5a141a0c1f9efa00ce21eb4/python_engineio-4.13.3-py3-none-any.whl", hash = "sha256:1f60ecaf1358190f0e26c48c578a60428dc02a8f1295bc3dbf53d1b31116821f", size = 59993, upload-time = "2026-06-20T22:53:50.775Z" }, +] + [[package]] name = "python-json-logger" version = "4.1.0" @@ -5063,11 +5931,33 @@ wheels = [ [[package]] name = "python-multipart" -version = "0.0.28" +version = "0.0.32" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/54/a85eb421fbdd5007bc5af39d0f4ed9fa609e0fedbfdc2adcf0b34526870e/python_multipart-0.0.28.tar.gz", hash = "sha256:8550da197eac0f7ab748961fc9509b999fa2662ea25cef857f05249f6893c0f8", size = 45314, upload-time = "2026-05-10T11:05:16.596Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/a2/43bbc5860b5034e2af4ef99a0e04d726ff329c43e192ef3abaa8d7ecfce5/python_multipart-0.0.28-py3-none-any.whl", hash = "sha256:10faac07eb966c3f48dc415f9dee46c04cb10d58d30a35677db8027c825ed9b6", size = 29438, upload-time = "2026-05-10T11:05:15.052Z" }, + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, +] + +[[package]] +name = "python-socketio" +version = "5.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bidict", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "python-engineio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/2d/ffce71017c106b75099fea569df6518c63fee5d6202ce0cfe7b01e6f22c3/python_socketio-5.16.3.tar.gz", hash = "sha256:89b136f677ae65607a84cecda9b4d6c5377b40a97582c504c25df89af16d520e", size = 128095, upload-time = "2026-06-15T22:07:04.003Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/38/8c5e72d53ff8eb27497c4f268a7f6d9121e727a50b65248288ad79a93053/python_socketio-5.16.3-py3-none-any.whl", hash = "sha256:e7ad14202a5e6448824c7c2f86161d04e13dec05992257df5c709e6a2798c041", size = 82087, upload-time = "2026-06-15T22:07:02.498Z" }, +] + +[package.optional-dependencies] +asyncio-client = [ + { name = "aiohttp", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +client = [ + { name = "requests", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "websocket-client", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] [[package]] @@ -5094,10 +5984,16 @@ 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/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]] @@ -5109,14 +6005,28 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, ] [[package]] @@ -5185,6 +6095,7 @@ dependencies = [ { name = "requests", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/95/898699cc1a6a5f304ea95376d079843b5c05f4c8c1ec7e55a5cc7ffcea50/ray-2.55.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:f9844a9272ef2e6eb5771025866072cf4234cf4c7cc1a31e235b7de7111864be", size = 65766823, upload-time = "2026-04-22T20:10:20.786Z" }, { url = "https://files.pythonhosted.org/packages/c9/13/87deecc090c672e45a0cf6f5eef511de448b93f37ef18fd10eb8e8557a0d/ray-2.55.1-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:b415d590e062f248907e0fe42994943f11726b7178fcf4b1cf5546721fb1a5f8", size = 72818676, upload-time = "2026-04-22T20:10:26.705Z" }, { url = "https://files.pythonhosted.org/packages/71/d7/fc95d3b8824c62105c64aa1b59c59600b581f608d78a2af753e010936dc9/ray-2.55.1-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:1380e043eb57cde69b7e9199c6f2558ceeb8f0fc41c97d1d5e50ea042115f302", size = 73678908, upload-time = "2026-04-22T20:10:32.795Z" }, ] @@ -5226,14 +6137,38 @@ version = "2026.5.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/da/797e91ecec6f84135da778ddce78c20e0af5d2a15c26f87a81bc3eadb6db/regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb", size = 490303, upload-time = "2026-05-09T23:13:04.382Z" }, + { url = "https://files.pythonhosted.org/packages/44/da/bf30abaaa737b58f4a4b8c4a03659e02fd92092c822e0197ed9e0daab917/regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f", size = 292019, upload-time = "2026-05-09T23:13:06.022Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e7/d0eaf5713828417b9e5648cf81fa9bacd4961f6ab98c380c2034f8716e35/regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c", size = 289468, upload-time = "2026-05-09T23:13:08.214Z" }, { url = "https://files.pythonhosted.org/packages/d3/9b/b3fdd62b003baa1a9b593cd8c8699c9651c2e80cc21a5c715707983c42d7/regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed", size = 796749, upload-time = "2026-05-09T23:13:10.573Z" }, + { url = "https://files.pythonhosted.org/packages/d4/30/66ab84588765f5b4b271a9ca09ef7ce2b87caa95176ec3d2ad65d7bc4902/regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020", size = 865445, upload-time = "2026-05-09T23:13:12.523Z" }, + { url = "https://files.pythonhosted.org/packages/1a/89/f05169e8588aac365f35ffc7f3bc3184f095ef4cfded7cfaa3c7fd5dbd89/regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2", size = 912322, upload-time = "2026-05-09T23:13:14.281Z" }, { url = "https://files.pythonhosted.org/packages/30/e1/c93444052cf41581f3c884ab3fb5823daf0992f11cd4388d4275ca610558/regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2", size = 801269, upload-time = "2026-05-09T23:13:16.569Z" }, + { url = "https://files.pythonhosted.org/packages/50/fe/0cf96b882f540e62e8b9956599798203d599c44cf4c77917ca27400ff69b/regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04", size = 777085, upload-time = "2026-05-09T23:13:18.675Z" }, { url = "https://files.pythonhosted.org/packages/23/5c/d78d4924e7fc875557b9e9b768423925fdfaac5549d06da7810019a9bd26/regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c", size = 785153, upload-time = "2026-05-09T23:13:20.525Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e0/5214774090e7b4524dcea3e3c4aa74141d43043f8beb49c1599db1c8b53a/regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f", size = 860164, upload-time = "2026-05-09T23:13:22.263Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e1/4a57a83350319b1271f0d7a249b8672513ed928b237a741631270de6caea/regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8", size = 765731, upload-time = "2026-05-09T23:13:24.277Z" }, + { url = "https://files.pythonhosted.org/packages/12/f4/499e74a20c156fc75836ee04a72a38d1a063978f600937f9760467beb1b0/regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6", size = 852062, upload-time = "2026-05-09T23:13:26.125Z" }, { url = "https://files.pythonhosted.org/packages/5b/92/7eebc0d0a01e78629695f342ba17e0deaff8fb45e79cc0d7b98287da6e3e/regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21", size = 789577, upload-time = "2026-05-09T23:13:27.814Z" }, + { url = "https://files.pythonhosted.org/packages/05/a4/018e71f7d2ad48c1ebe6d3ae0026f9b7cb4802fd15c7cc02fdf724355102/regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127", size = 266691, upload-time = "2026-05-09T23:13:29.549Z" }, + { url = "https://files.pythonhosted.org/packages/e6/1d/861a93719fb9ee7dbfc3761b3797b7a3e112a5d42c6129459d2d741be9b5/regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca", size = 277747, upload-time = "2026-05-09T23:13:31.859Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c6/0a2436ae4da1ba76e51cb98943c6838a9a721faa40ebe2dce07694ae34e3/regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6", size = 270500, upload-time = "2026-05-09T23:13:33.525Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e9/d21346f7b60ed58789371358ed66b09d00f832e1bd7c06e55d9da5679882/regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3", size = 494172, upload-time = "2026-05-09T23:13:35.935Z" }, + { url = "https://files.pythonhosted.org/packages/c4/43/fd1177a2032037c681baecdb3422ee4e1424aec4e4f470ef47793d325274/regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6", size = 293952, upload-time = "2026-05-09T23:13:38.307Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7d/9fbf919768368d3f8a4f6c692cf2aa61e482b2b81ec6a298ace4cbf02480/regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff", size = 292314, upload-time = "2026-05-09T23:13:40.353Z" }, { url = "https://files.pythonhosted.org/packages/e2/6c/e41bfeecb589716843e7c4df09ba46ff2a42961457afece19059d85caeef/regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88", size = 811681, upload-time = "2026-05-09T23:13:42.543Z" }, + { url = "https://files.pythonhosted.org/packages/87/83/a5c1c525fba0aa656e88ad0face0b1829788ef4c2fb6b26df58aa1151b84/regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178", size = 871135, upload-time = "2026-05-09T23:13:44.326Z" }, + { url = "https://files.pythonhosted.org/packages/18/d4/80882e799e440dd878b0979cbebf8fa4d54624a332c83037c7a701649e3f/regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100", size = 917265, upload-time = "2026-05-09T23:13:47.295Z" }, { url = "https://files.pythonhosted.org/packages/ae/ff/8db60211e2286e396aad7dc7725356c502bff0901ea05bd6cdc2e1a042b9/regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e", size = 816311, upload-time = "2026-05-09T23:13:49.885Z" }, + { url = "https://files.pythonhosted.org/packages/4c/47/742ef579c61730f8d268e5cf1f9ce0e37e2ea041ad0f5644724f2378e463/regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2", size = 785498, upload-time = "2026-05-09T23:13:52.25Z" }, { url = "https://files.pythonhosted.org/packages/7f/ab/cb0999802dcb0fb95b1ab005e8d4163d8afdd67efc2cb6b6630ac13f8cb1/regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b", size = 801348, upload-time = "2026-05-09T23:13:54.127Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/8ca59a24c55bc34d166eefaf3717bd77772f329fdbf984d86581e0a3571c/regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e", size = 866493, upload-time = "2026-05-09T23:13:56.067Z" }, + { url = "https://files.pythonhosted.org/packages/8d/3d/30f2ae62cef3278bb5bb821f467277a55fb73f01032cf85997e15e8289a8/regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041", size = 772811, upload-time = "2026-05-09T23:13:57.867Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ae/7d2089bcd78ad0c0161bc684339df50032acb438a7bd3305e7ddb1193cec/regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0", size = 856584, upload-time = "2026-05-09T23:13:59.679Z" }, { url = "https://files.pythonhosted.org/packages/a9/29/92ff47f75990131ea4f24ba17819e5a9d141e10819807e09addd73409af6/regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081", size = 803453, upload-time = "2026-05-09T23:14:01.978Z" }, + { url = "https://files.pythonhosted.org/packages/04/99/eff29f1037dcab36702c9ee5d6858cf1ce2336ea8ea2987f64245b99ea5e/regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5", size = 269951, upload-time = "2026-05-09T23:14:03.661Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9d/8870b8981d27b22cda77bb26a5ac7ebfa9c7d9e0dea195a834a82380e748/regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4", size = 281240, upload-time = "2026-05-09T23:14:05.56Z" }, + { url = "https://files.pythonhosted.org/packages/72/b1/3379415e8f135c13ac551353397cc4fe97b4978f3cac73c5fcbcded548b8/regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de", size = 272383, upload-time = "2026-05-09T23:14:07.843Z" }, ] [[package]] @@ -5308,10 +6243,21 @@ version = "0.7.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/8a/a4078f6e14932ac7edb171149c481de29969d96ddee3ece5dc4c26f9e0c3/rignore-0.7.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2bdab1d31ec9b4fb1331980ee49ea051c0d7f7bb6baa28b3125ef03cdc48fdaf", size = 883057, upload-time = "2025-11-05T20:42:42.741Z" }, + { url = "https://files.pythonhosted.org/packages/f9/8f/f8daacd177db4bf7c2223bab41e630c52711f8af9ed279be2058d2fe4982/rignore-0.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90f0a00ce0c866c275bf888271f1dc0d2140f29b82fcf33cdbda1e1a6af01010", size = 820150, upload-time = "2025-11-05T20:42:26.545Z" }, { url = "https://files.pythonhosted.org/packages/36/31/b65b837e39c3f7064c426754714ac633b66b8c2290978af9d7f513e14aa9/rignore-0.7.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ad295537041dc2ed4b540fb1a3906bd9ede6ccdad3fe79770cd89e04e3c73c", size = 897406, upload-time = "2025-11-05T20:40:53.854Z" }, + { url = "https://files.pythonhosted.org/packages/ca/58/1970ce006c427e202ac7c081435719a076c478f07b3a23f469227788dc23/rignore-0.7.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f782dbd3a65a5ac85adfff69e5c6b101285ef3f845c3a3cae56a54bebf9fe116", size = 874050, upload-time = "2025-11-05T20:41:08.922Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/eb45db9f90137329072a732273be0d383cb7d7f50ddc8e0bceea34c1dfdf/rignore-0.7.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65cece3b36e5b0826d946494734c0e6aaf5a0337e18ff55b071438efe13d559e", size = 1167835, upload-time = "2025-11-05T20:41:24.997Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f1/6f1d72ddca41a64eed569680587a1236633587cc9f78136477ae69e2c88a/rignore-0.7.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e4bb66c13cd7602dc8931822c02dfbbd5252015c750ac5d6152b186f0a8be0", size = 941945, upload-time = "2025-11-05T20:41:40.628Z" }, { url = "https://files.pythonhosted.org/packages/48/6f/2f178af1c1a276a065f563ec1e11e7a9e23d4996fd0465516afce4b5c636/rignore-0.7.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297e500c15766e196f68aaaa70e8b6db85fa23fdc075b880d8231fdfba738cd7", size = 959067, upload-time = "2025-11-05T20:42:11.09Z" }, + { url = "https://files.pythonhosted.org/packages/5b/db/423a81c4c1e173877c7f9b5767dcaf1ab50484a94f60a0b2ed78be3fa765/rignore-0.7.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a07084211a8d35e1a5b1d32b9661a5ed20669970b369df0cf77da3adea3405de", size = 984438, upload-time = "2025-11-05T20:41:55.443Z" }, { url = "https://files.pythonhosted.org/packages/31/eb/c4f92cc3f2825d501d3c46a244a671eb737fc1bcf7b05a3ecd34abb3e0d7/rignore-0.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:181eb2a975a22256a1441a9d2f15eb1292839ea3f05606620bd9e1938302cf79", size = 1078365, upload-time = "2025-11-05T21:40:15.148Z" }, + { url = "https://files.pythonhosted.org/packages/26/09/99442f02794bd7441bfc8ed1c7319e890449b816a7493b2db0e30af39095/rignore-0.7.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7bbcdc52b5bf9f054b34ce4af5269df5d863d9c2456243338bc193c28022bd7b", size = 1139066, upload-time = "2025-11-05T21:40:32.771Z" }, + { url = "https://files.pythonhosted.org/packages/2c/88/bcfc21e520bba975410e9419450f4b90a2ac8236b9a80fd8130e87d098af/rignore-0.7.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f2e027a6da21a7c8c0d87553c24ca5cc4364def18d146057862c23a96546238e", size = 1118036, upload-time = "2025-11-05T21:40:49.646Z" }, { url = "https://files.pythonhosted.org/packages/e2/25/d37215e4562cda5c13312636393aea0bafe38d54d4e0517520a4cc0753ec/rignore-0.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee4a18b82cbbc648e4aac1510066682fe62beb5dc88e2c67c53a83954e541360", size = 1127550, upload-time = "2025-11-05T21:41:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/dc/76/a264ab38bfa1620ec12a8ff1c07778da89e16d8c0f3450b0333020d3d6dc/rignore-0.7.6-cp313-cp313-win32.whl", hash = "sha256:a7d7148b6e5e95035d4390396895adc384d37ff4e06781a36fe573bba7c283e5", size = 646097, upload-time = "2025-11-05T21:41:53.201Z" }, + { url = "https://files.pythonhosted.org/packages/62/44/3c31b8983c29ea8832b6082ddb1d07b90379c2d993bd20fce4487b71b4f4/rignore-0.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:b037c4b15a64dced08fc12310ee844ec2284c4c5c1ca77bc37d0a04f7bff386e", size = 726170, upload-time = "2025-11-05T21:41:38.131Z" }, + { url = "https://files.pythonhosted.org/packages/aa/41/e26a075cab83debe41a42661262f606166157df84e0e02e2d904d134c0d8/rignore-0.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:e47443de9b12fe569889bdbe020abe0e0b667516ee2ab435443f6d0869bd2804", size = 656184, upload-time = "2025-11-05T21:41:27.396Z" }, ] [[package]] @@ -5329,14 +6275,35 @@ 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/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" }, ] [[package]] @@ -5345,10 +6312,35 @@ version = "0.9.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6f/c3/418441a8170e8d53d05c0b9dad69760dbc7b8a12c10dbe6db1e1205d2377/ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933", size = 3717448, upload-time = "2025-02-28T10:16:42.209Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/c3/2c4afa9ba467555d074b146d9aed0633a56ccdb900839fb008295d037b89/ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367", size = 10027252, upload-time = "2025-02-28T10:15:44.182Z" }, + { url = "https://files.pythonhosted.org/packages/33/d1/439e58487cf9eac26378332e25e7d5ade4b800ce1eec7dc2cfc9b0d7ca96/ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7", size = 10840721, upload-time = "2025-02-28T10:15:49.396Z" }, + { url = "https://files.pythonhosted.org/packages/50/44/fead822c38281ba0122f1b76b460488a175a9bd48b130650a6fb6dbcbcf9/ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d", size = 10161439, upload-time = "2025-02-28T10:15:52.522Z" }, { url = "https://files.pythonhosted.org/packages/11/ae/d404a2ab8e61ddf6342e09cc6b7f7846cce6b243e45c2007dbe0ca928a5d/ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a", size = 10336264, upload-time = "2025-02-28T10:15:56.9Z" }, + { url = "https://files.pythonhosted.org/packages/6a/4e/7c268aa7d84cd709fb6f046b8972313142cffb40dfff1d2515c5e6288d54/ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe", size = 9908774, upload-time = "2025-02-28T10:15:59.612Z" }, + { url = "https://files.pythonhosted.org/packages/cc/26/c618a878367ef1b76270fd027ca93692657d3f6122b84ba48911ef5f2edc/ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c", size = 11428127, upload-time = "2025-02-28T10:16:02.94Z" }, + { url = "https://files.pythonhosted.org/packages/d7/9a/c5588a93d9bfed29f565baf193fe802fa676a0c837938137ea6cf0576d8c/ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be", size = 12133187, upload-time = "2025-02-28T10:16:05.632Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ff/e7980a7704a60905ed7e156a8d73f604c846d9bd87deda9cabfa6cba073a/ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590", size = 11602937, upload-time = "2025-02-28T10:16:10.489Z" }, + { url = "https://files.pythonhosted.org/packages/24/78/3690444ad9e3cab5c11abe56554c35f005b51d1d118b429765249095269f/ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb", size = 13771698, upload-time = "2025-02-28T10:16:13.358Z" }, { url = "https://files.pythonhosted.org/packages/6e/bf/e477c2faf86abe3988e0b5fd22a7f3520e820b2ee335131aca2e16120038/ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0", size = 11249026, upload-time = "2025-02-28T10:16:16.154Z" }, { url = "https://files.pythonhosted.org/packages/f7/82/cdaffd59e5a8cb5b14c408c73d7a555a577cf6645faaf83e52fe99521715/ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17", size = 10220432, upload-time = "2025-02-28T10:16:18.798Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a4/2507d0026225efa5d4412b6e294dfe54725a78652a5c7e29e6bd0fc492f3/ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1", size = 9874602, upload-time = "2025-02-28T10:16:21.903Z" }, + { url = "https://files.pythonhosted.org/packages/d5/be/f3aab1813846b476c4bcffe052d232244979c3cd99d751c17afb530ca8e4/ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57", size = 10851212, upload-time = "2025-02-28T10:16:24.793Z" }, { url = "https://files.pythonhosted.org/packages/8b/45/8e5fd559bea0d2f57c4e12bf197a2fade2fac465aa518284f157dfbca92b/ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e", size = 11327490, upload-time = "2025-02-28T10:16:27.654Z" }, + { url = "https://files.pythonhosted.org/packages/42/55/e6c90f13880aeef327746052907e7e930681f26a164fe130ddac28b08269/ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1", size = 10227912, upload-time = "2025-02-28T10:16:31.55Z" }, + { url = "https://files.pythonhosted.org/packages/35/b2/da925693cb82a1208aa34966c0f36cb222baca94e729dd22a587bc22d0f3/ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1", size = 11355632, upload-time = "2025-02-28T10:16:36.144Z" }, + { url = "https://files.pythonhosted.org/packages/31/d8/de873d1c1b020d668d8ec9855d390764cb90cf8f6486c0983da52be8b7b7/ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf", size = 10435860, upload-time = "2025-02-28T10:16:39.481Z" }, +] + +[[package]] +name = "s3transfer" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/43/35e4d8aa320bffe8287fe8f65f578fa2d2db0a64212f0e710dce58267854/s3transfer-0.19.2.tar.gz", hash = "sha256:ba0309fd86be3c27dbf78cdd813c13c5e1df16e5874b99d2535ebbdfb9892993", size = 165592, upload-time = "2026-07-22T19:30:44.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl", hash = "sha256:d8168eccca828cbb2cd573675333f3bddd254313a9c42494b84c76b539e8ba25", size = 90216, upload-time = "2026-07-22T19:30:43.251Z" }, ] [[package]] @@ -5357,10 +6349,22 @@ version = "0.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, ] [[package]] @@ -5375,10 +6379,18 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/03/aa/e22e0768512ce9255eba34775be2e85c2048da73da1193e841707f8f039c/scikit_learn-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d6ae97234d5d7079dc0040990a6f7aeb97cb7fa7e8945f1999a429b23569e0a", size = 8513770, upload-time = "2025-12-10T07:08:03.251Z" }, + { url = "https://files.pythonhosted.org/packages/58/37/31b83b2594105f61a381fc74ca19e8780ee923be2d496fcd8d2e1147bd99/scikit_learn-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:edec98c5e7c128328124a029bceb09eda2d526997780fef8d65e9a69eead963e", size = 8044458, upload-time = "2025-12-10T07:08:05.336Z" }, { url = "https://files.pythonhosted.org/packages/2d/5a/3f1caed8765f33eabb723596666da4ebbf43d11e96550fb18bdec42b467b/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74b66d8689d52ed04c271e1329f0c61635bcaf5b926db9b12d58914cdc01fe57", size = 8610341, upload-time = "2025-12-10T07:08:07.732Z" }, { url = "https://files.pythonhosted.org/packages/38/cf/06896db3f71c75902a8e9943b444a56e727418f6b4b4a90c98c934f51ed4/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8fdf95767f989b0cfedb85f7ed8ca215d4be728031f56ff5a519ee1e3276dc2e", size = 8900022, upload-time = "2025-12-10T07:08:09.862Z" }, + { url = "https://files.pythonhosted.org/packages/1c/f9/9b7563caf3ec8873e17a31401858efab6b39a882daf6c1bfa88879c0aa11/scikit_learn-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:2de443b9373b3b615aec1bb57f9baa6bb3a9bd093f1269ba95c17d870422b271", size = 7989409, upload-time = "2025-12-10T07:08:12.028Z" }, + { url = "https://files.pythonhosted.org/packages/49/bd/1f4001503650e72c4f6009ac0c4413cb17d2d601cef6f71c0453da2732fc/scikit_learn-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:eddde82a035681427cbedded4e6eff5e57fa59216c2e3e90b10b19ab1d0a65c3", size = 7619760, upload-time = "2025-12-10T07:08:13.688Z" }, + { url = "https://files.pythonhosted.org/packages/d2/7d/a630359fc9dcc95496588c8d8e3245cc8fd81980251079bc09c70d41d951/scikit_learn-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7cc267b6108f0a1499a734167282c00c4ebf61328566b55ef262d48e9849c735", size = 8826045, upload-time = "2025-12-10T07:08:15.215Z" }, + { url = "https://files.pythonhosted.org/packages/cc/56/a0c86f6930cfcd1c7054a2bc417e26960bb88d32444fe7f71d5c2cfae891/scikit_learn-1.8.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:fe1c011a640a9f0791146011dfd3c7d9669785f9fed2b2a5f9e207536cf5c2fd", size = 8420324, upload-time = "2025-12-10T07:08:17.561Z" }, { url = "https://files.pythonhosted.org/packages/46/1e/05962ea1cebc1cf3876667ecb14c283ef755bf409993c5946ade3b77e303/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72358cce49465d140cc4e7792015bb1f0296a9742d5622c67e31399b75468b9e", size = 8680651, upload-time = "2025-12-10T07:08:19.952Z" }, { url = "https://files.pythonhosted.org/packages/fe/56/a85473cd75f200c9759e3a5f0bcab2d116c92a8a02ee08ccd73b870f8bb4/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80832434a6cc114f5219211eec13dcbc16c2bac0e31ef64c6d346cde3cf054cb", size = 8925045, upload-time = "2025-12-10T07:08:22.11Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b7/64d8cfa896c64435ae57f4917a548d7ac7a44762ff9802f75a79b77cb633/scikit_learn-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ee787491dbfe082d9c3013f01f5991658b0f38aa8177e4cd4bf434c58f551702", size = 8507994, upload-time = "2025-12-10T07:08:23.943Z" }, + { url = "https://files.pythonhosted.org/packages/5e/37/e192ea709551799379958b4c4771ec507347027bb7c942662c7fbeba31cb/scikit_learn-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf97c10a3f5a7543f9b88cbf488d33d175e9146115a451ae34568597ba33dcde", size = 7869518, upload-time = "2025-12-10T07:08:25.71Z" }, ] [[package]] @@ -5390,14 +6402,26 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, + { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, + { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, + { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, + { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, + { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, + { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, ] [[package]] @@ -5415,10 +6439,22 @@ version = "0.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/15/15/2e7a025fc62d764b151ae6d0f2a92f8081755ebe8d4a64099accc6f77ba6/sentencepiece-0.2.1.tar.gz", hash = "sha256:8138cec27c2f2282f4a34d9a016e3374cd40e5c6e9cb335063db66a0a3b71fad", size = 3228515, upload-time = "2025-08-12T07:00:51.718Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/4a/85fbe1706d4d04a7e826b53f327c4b80f849cf1c7b7c5e31a20a97d8f28b/sentencepiece-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dcd8161eee7b41aae57ded06272905dbd680a0a04b91edd0f64790c796b2f706", size = 1943150, upload-time = "2025-08-12T06:59:53.588Z" }, + { url = "https://files.pythonhosted.org/packages/c2/83/4cfb393e287509fc2155480b9d184706ef8d9fa8cbf5505d02a5792bf220/sentencepiece-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c6c8f42949f419ff8c7e9960dbadcfbc982d7b5efc2f6748210d3dd53a7de062", size = 1325651, upload-time = "2025-08-12T06:59:55.073Z" }, + { url = "https://files.pythonhosted.org/packages/8d/de/5a007fb53b1ab0aafc69d11a5a3dd72a289d5a3e78dcf2c3a3d9b14ffe93/sentencepiece-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:097f3394e99456e9e4efba1737c3749d7e23563dd1588ce71a3d007f25475fff", size = 1253641, upload-time = "2025-08-12T06:59:56.562Z" }, { url = "https://files.pythonhosted.org/packages/2c/d2/f552be5928105588f4f4d66ee37dd4c61460d8097e62d0e2e0eec41bc61d/sentencepiece-0.2.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7b670879c370d350557edabadbad1f6561a9e6968126e6debca4029e5547820", size = 1316271, upload-time = "2025-08-12T06:59:58.109Z" }, { url = "https://files.pythonhosted.org/packages/96/df/0cfe748ace5485be740fed9476dee7877f109da32ed0d280312c94ec259f/sentencepiece-0.2.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7f0fd2f2693309e6628aeeb2e2faf6edd221134dfccac3308ca0de01f8dab47", size = 1387882, upload-time = "2025-08-12T07:00:00.701Z" }, + { url = "https://files.pythonhosted.org/packages/ac/dd/f7774d42a881ced8e1739f393ab1e82ece39fc9abd4779e28050c2e975b5/sentencepiece-0.2.1-cp313-cp313-win32.whl", hash = "sha256:92b3816aa2339355fda2c8c4e021a5de92180b00aaccaf5e2808972e77a4b22f", size = 999541, upload-time = "2025-08-12T07:00:02.709Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e9/932b9eae6fd7019548321eee1ab8d5e3b3d1294df9d9a0c9ac517c7b636d/sentencepiece-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:10ed3dab2044c47f7a2e7b4969b0c430420cdd45735d78c8f853191fa0e3148b", size = 1054669, upload-time = "2025-08-12T07:00:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/c9/3a/76488a00ea7d6931689cda28726a1447d66bf1a4837943489314593d5596/sentencepiece-0.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac650534e2251083c5f75dde4ff28896ce7c8904133dc8fef42780f4d5588fcd", size = 1033922, upload-time = "2025-08-12T07:00:06.496Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b6/08fe2ce819e02ccb0296f4843e3f195764ce9829cbda61b7513f29b95718/sentencepiece-0.2.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:8dd4b477a7b069648d19363aad0cab9bad2f4e83b2d179be668efa672500dc94", size = 1946052, upload-time = "2025-08-12T07:00:08.136Z" }, + { url = "https://files.pythonhosted.org/packages/ab/d9/1ea0e740591ff4c6fc2b6eb1d7510d02f3fb885093f19b2f3abd1363b402/sentencepiece-0.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0c0f672da370cc490e4c59d89e12289778310a0e71d176c541e4834759e1ae07", size = 1327408, upload-time = "2025-08-12T07:00:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/99/7e/1fb26e8a21613f6200e1ab88824d5d203714162cf2883248b517deb500b7/sentencepiece-0.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad8493bea8432dae8d6830365352350f3b4144415a1d09c4c8cb8d30cf3b6c3c", size = 1254857, upload-time = "2025-08-12T07:00:11.021Z" }, { url = "https://files.pythonhosted.org/packages/bc/85/c72fd1f3c7a6010544d6ae07f8ddb38b5e2a7e33bd4318f87266c0bbafbf/sentencepiece-0.2.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b81a24733726e3678d2db63619acc5a8dccd074f7aa7a54ecd5ca33ca6d2d596", size = 1315722, upload-time = "2025-08-12T07:00:12.989Z" }, { url = "https://files.pythonhosted.org/packages/4a/e8/661e5bd82a8aa641fd6c1020bd0e890ef73230a2b7215ddf9c8cd8e941c2/sentencepiece-0.2.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0a81799d0a68d618e89063fb423c3001a034c893069135ffe51fee439ae474d6", size = 1387452, upload-time = "2025-08-12T07:00:15.088Z" }, + { url = "https://files.pythonhosted.org/packages/99/5e/ae66c361023a470afcbc1fbb8da722c72ea678a2fcd9a18f1a12598c7501/sentencepiece-0.2.1-cp313-cp313t-win32.whl", hash = "sha256:89a3ea015517c42c0341d0d962f3e6aaf2cf10d71b1932d475c44ba48d00aa2b", size = 1002501, upload-time = "2025-08-12T07:00:16.966Z" }, + { url = "https://files.pythonhosted.org/packages/c1/03/d332828c4ff764e16c1b56c2c8f9a33488bbe796b53fb6b9c4205ddbf167/sentencepiece-0.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:33f068c9382dc2e7c228eedfd8163b52baa86bb92f50d0488bf2b7da7032e484", size = 1057555, upload-time = "2025-08-12T07:00:18.573Z" }, + { url = "https://files.pythonhosted.org/packages/88/14/5aee0bf0864df9bd82bd59e7711362908e4935e3f9cdc1f57246b5d5c9b9/sentencepiece-0.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:b3616ad246f360e52c85781e47682d31abfb6554c779e42b65333d4b5f44ecc0", size = 1036042, upload-time = "2025-08-12T07:00:20.209Z" }, ] [[package]] @@ -5440,14 +6476,26 @@ version = "1.3.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" }, + { url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" }, { url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" }, { url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" }, + { url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" }, { url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" }, + { url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" }, { url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" }, + { url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" }, + { url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" }, + { url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" }, { url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" }, { url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" }, + { url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" }, { url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" }, + { url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" }, { url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" }, + { url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" }, + { url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" }, ] [[package]] @@ -5571,10 +6619,13 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e2/14/19020d822877810d1b047073bb41c54a76802e618296af12344f6caa6d2e/sglang_router-0.3.2.tar.gz", hash = "sha256:bdbea1d54cce879fb83d2885d01ee3c006f242d0adbbac806f2fb2b91a5fe73d", size = 1301869, upload-time = "2026-01-15T19:55:17.856Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/33/1f206e3238a709f0f032f5c2a4c9115a5af12245781a5c8eea9a4e692b6f/sglang_router-0.3.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:111cf062d018ec307b1427c7211c62696447feda13614a84c24f60a5d7907319", size = 27594300, upload-time = "2026-01-15T19:55:00.149Z" }, + { url = "https://files.pythonhosted.org/packages/e6/57/5f6ab7f6940ff1612c94fe250170a026ecdf6bf63fa25f1ebd917579112c/sglang_router-0.3.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:027e498713affb0f7f3ddf72ce7b14f499080137784c258b26321ec8c18d533b", size = 26307573, upload-time = "2026-01-15T19:55:02.879Z" }, { url = "https://files.pythonhosted.org/packages/e7/4f/3e87054427e06f7dd1cc089514d4e29f7946c7c9916009d5fbd3997be6a3/sglang_router-0.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40a10f3817b80377c2ceb326b625f24bd06eb97426e5044de722295ec7fa79c0", size = 31039654, upload-time = "2026-01-15T19:55:05.393Z" }, { url = "https://files.pythonhosted.org/packages/21/37/2ec21a57e77f7bb66c713a819ea6ffa94b6859c6b3ddd062d3b91d856b86/sglang_router-0.3.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba5a24951e5e0357fe390782fcd1abd861448a87216832dbf2e501a1dd1548eb", size = 30726976, upload-time = "2026-01-15T19:55:07.886Z" }, { url = "https://files.pythonhosted.org/packages/91/de/7774e5909ef986e1fe3f2618e4c47d3d97cdf1efaa7909f60a73fc7afac7/sglang_router-0.3.2-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:415be7ed1415a0c931155d2bc8abd74e467a074066b41d956ca944eedbcc9b4b", size = 37141388, upload-time = "2026-01-15T19:55:10.393Z" }, { url = "https://files.pythonhosted.org/packages/47/fb/485c074c67db41d7582760443dcf98e2cf42793b82e699935f48ff04f3b6/sglang_router-0.3.2-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:366183fc84865028b6e63d62adc8ce603667abf0162c393170c8c63be1582a49", size = 38289376, upload-time = "2026-01-15T19:55:12.897Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5f/813b620900310edf41a431f42a7b32f75c793239cb60c454f52f03a52c44/sglang_router-0.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:037f028d6f0e5bae8a84259b49d9857a5427c84653c2d02023fed623ae221530", size = 25838819, upload-time = "2026-01-15T19:55:15.927Z" }, ] [[package]] @@ -5586,16 +6637,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] +[[package]] +name = "simple-websocket" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wsproto", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300, upload-time = "2024-10-10T22:39:31.412Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842, upload-time = "2024-10-10T22:39:29.645Z" }, +] + [[package]] name = "simplejson" version = "4.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0e/2a/54837395a3487c725669428d513293612a48d82b95a0642c936932e5d898/simplejson-4.1.1.tar.gz", hash = "sha256:c08eb9f7a90f77ae470e19a07472e9a79ebc0d1c2315d86a72767665bd5ba79f", size = 118860, upload-time = "2026-04-24T19:24:59.819Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/37/a9/47b445eeb559c9593453a0648e0fd6d08e8adff64dd5e5ced66726da8a09/simplejson-4.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dff52fc7af272e84fc21cc5a06c927c823ca6ae00af14f3b0d7707b42775ed98", size = 113160, upload-time = "2026-04-24T19:23:26.033Z" }, + { url = "https://files.pythonhosted.org/packages/4c/65/cb72db31523c164dea5dc55b02dad065a40c478856bc7534b279d2b51906/simplejson-4.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:971aed0647ad6e840a3943bec812fcda5f2d26a5497a4981d1fb49aa4f9a396c", size = 91521, upload-time = "2026-04-24T19:23:27.572Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e5/54cb7c50ad5fdc1e0a86b7df4b135c2cbd5c4623605aa94466659098e8da/simplejson-4.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:249e2e220aa6d9b9d936bde84eb7bf79d5b6c5a8273c6e411f8b1635a9073f2d", size = 91407, upload-time = "2026-04-24T19:23:28.991Z" }, { url = "https://files.pythonhosted.org/packages/38/2e/21a3ede87f0bf82d6c7bcb90480d50a6490eb974c6ab20881188e440957c/simplejson-4.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e5cdd6a5d52299f345c15ab5678cc4249e24f383f361d986afbc3c7072a6b6b", size = 192451, upload-time = "2026-04-24T19:23:30.56Z" }, { url = "https://files.pythonhosted.org/packages/59/df/9903edd3102bf0b5984edfcb90c88612330996efa3b4fbf8a971d6e17839/simplejson-4.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:642cec364e0676e2d5a73fa4d31d0c7c55886997caa2fde24e8292ca44d32728", size = 189015, upload-time = "2026-04-24T19:23:32.647Z" }, + { url = "https://files.pythonhosted.org/packages/98/cd/33230927a780e1398b857e3944abb914556994d252b1d765ae40d112cb25/simplejson-4.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:76fe296ca1df23d290033f10aaacf534fd1b3e3007e7f9ff8aa68b21413aaa78", size = 196658, upload-time = "2026-04-24T19:23:34.563Z" }, { url = "https://files.pythonhosted.org/packages/cd/84/2c5a7444eb53e9a86d3738299bffddd9f53aeed799ded2f45368221fdb19/simplejson-4.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f0ad25b7dc4e0fb23858355819f2e994f1a5badcdcde8737eac7921c2f1ed2a", size = 185967, upload-time = "2026-04-24T19:23:36.191Z" }, + { url = "https://files.pythonhosted.org/packages/d3/68/454378e06d059cd412a7ed5d87fb6d29fd5b60f13a4d89fc1f764ff434df/simplejson-4.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a59ebd0533f03fd06ff0c42ba0f02d93cbcdd7944922bf3b93911327a95b901f", size = 193940, upload-time = "2026-04-24T19:23:38.151Z" }, { url = "https://files.pythonhosted.org/packages/d5/d5/a15bf915f623a2c5a079d6e3be8256fdb8ef06f110669493a09b9d6933e0/simplejson-4.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bccbf4419676b517939852e5aeff2af6aee4dc046881c67a1581fa6f1cb01abd", size = 189795, upload-time = "2026-04-24T19:23:40.139Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c9/37212ae7dc4b607f0978c408e8633f05c810884e054c33113184c6c2c8a2/simplejson-4.1.1-cp313-cp313-win32.whl", hash = "sha256:6c845363eb5fd166fb7c72243da38f4fcfde666ede7fdf2cc6fd7762894626f7", size = 88773, upload-time = "2026-04-24T19:23:41.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a5/c7a0a47883a9015b54c9d8a4b62f2aba17bd4335b1787b9b8a0fc2fa6d52/simplejson-4.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:104d8324c34f25b4b90800bc5fa363780cbc3d8496aef061cba7ce1af9162270", size = 90888, upload-time = "2026-04-24T19:23:43.11Z" }, { url = "https://files.pythonhosted.org/packages/ce/6a/8b74c52ffd33dbbde00fe7251fee6a0acdc8cea33f7a43805aed258fb79b/simplejson-4.1.1-py3-none-any.whl", hash = "sha256:2ce92b3748f02423e26d2bfb636fb9d7a8f67c8f5854dcae69d350d123b2eee2", size = 69195, upload-time = "2026-04-24T19:24:57.962Z" }, ] @@ -5702,8 +6772,12 @@ dependencies = [ sdist = { url = "https://files.pythonhosted.org/packages/e1/41/9b873a8c055582859b239be17902a85339bec6a30ad162f98c9b0288a2cc/soundfile-0.13.1.tar.gz", hash = "sha256:b2c68dab1e30297317080a5b43df57e302584c49e2942defdde0acccc53f0e5b", size = 46156, upload-time = "2025-01-25T09:17:04.831Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/64/28/e2a36573ccbcf3d57c00626a21fe51989380636e821b341d36ccca0c1c3a/soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445", size = 25751, upload-time = "2025-01-25T09:16:44.235Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ab/73e97a5b3cc46bba7ff8650a1504348fa1863a6f9d57d7001c6b67c5f20e/soundfile-0.13.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:82dc664d19831933fe59adad199bf3945ad06d84bc111a5b4c0d3089a5b9ec33", size = 1142250, upload-time = "2025-01-25T09:16:47.583Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e5/58fd1a8d7b26fc113af244f966ee3aecf03cb9293cb935daaddc1e455e18/soundfile-0.13.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:743f12c12c4054921e15736c6be09ac26b3b3d603aef6fd69f9dde68748f2593", size = 1101406, upload-time = "2025-01-25T09:16:49.662Z" }, { url = "https://files.pythonhosted.org/packages/58/ae/c0e4a53d77cf6e9a04179535766b3321b0b9ced5f70522e4caf9329f0046/soundfile-0.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9c9e855f5a4d06ce4213f31918653ab7de0c5a8d8107cd2427e44b42df547deb", size = 1235729, upload-time = "2025-01-25T09:16:53.018Z" }, { url = "https://files.pythonhosted.org/packages/57/5e/70bdd9579b35003a489fc850b5047beeda26328053ebadc1fb60f320f7db/soundfile-0.13.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:03267c4e493315294834a0870f31dbb3b28a95561b80b134f0bd3cf2d5f0e618", size = 1313646, upload-time = "2025-01-25T09:16:54.872Z" }, + { url = "https://files.pythonhosted.org/packages/fe/df/8c11dc4dfceda14e3003bb81a0d0edcaaf0796dd7b4f826ea3e532146bba/soundfile-0.13.1-py2.py3-none-win32.whl", hash = "sha256:c734564fab7c5ddf8e9be5bf70bab68042cd17e9c214c06e365e20d64f9a69d5", size = 899881, upload-time = "2025-01-25T09:16:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/14/e9/6b761de83277f2f02ded7e7ea6f07828ec78e4b229b80e4ca55dd205b9dc/soundfile-0.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:1e70a05a0626524a69e9f0f4dd2ec174b4e9567f4d8b6c11d38b5c289be36ee9", size = 1019162, upload-time = "2025-01-25T09:16:59.573Z" }, ] [[package]] @@ -5724,8 +6798,11 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/ed/11/27cebce4a108f77afea7c80545115536b45e3f11ebfb914f638fdd9ba847/soxr-1.1.0.tar.gz", hash = "sha256:9f228ae21c78fa9359ca98d8a5e8e91f30639e438e574133dace62c5b5309e44", size = 173067, upload-time = "2026-05-03T00:15:18.214Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/06/8a/f3da7973b5f1b05d2d7e94d5376b881dcbc05297900cae6c3d33d95b209b/soxr-1.1.0-cp312-abi3-macosx_10_14_x86_64.whl", hash = "sha256:e0e09fa633ce2e67df08b298afced4d184f6e753fc330f241022250f1d0d61da", size = 204124, upload-time = "2026-05-03T00:14:54.505Z" }, + { url = "https://files.pythonhosted.org/packages/03/dc/200013a74641f8774664bbcd2346c695c05c2e300ea792adcb40a293eed0/soxr-1.1.0-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6a7ad82b8d5f3fcc04b1d2ca055562b96af571e1d4fa7c6c61d0fb509ac43b4", size = 165457, upload-time = "2026-05-03T00:14:56.007Z" }, { url = "https://files.pythonhosted.org/packages/88/2b/2e5eba817a762a2ec589ff165b8bc5955b25a0ad140045f7cd8e45410543/soxr-1.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf98c0d7b7d5ef5bf072fee8d3020e8b664f2d195933ea7bc5089267c2e22a06", size = 206529, upload-time = "2026-05-03T00:14:57.646Z" }, { url = "https://files.pythonhosted.org/packages/5c/f1/0e55195893228609c9a08c3b13b7a83a46c3a992cd00d3304f0f320cfb07/soxr-1.1.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b033078e86f3c4a658e5697fac8995764fad9e799563616b630136b613167f1", size = 240413, upload-time = "2026-05-03T00:14:59.363Z" }, + { url = "https://files.pythonhosted.org/packages/b0/4d/621e4150e4815246ad552d215a8a294a90143fedd19ee442cf82d3b3abc8/soxr-1.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:6ae2a174bffea94e8ead857dad85999d3f49f091774dbad5b046c0417d7092f4", size = 174357, upload-time = "2026-05-03T00:15:00.724Z" }, ] [[package]] @@ -5762,8 +6839,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "sphinx", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "starlette", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "uvicorn", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "watchfiles", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, { name = "websockets", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, @@ -5900,14 +6976,19 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/81/81755f50eb2478eaf2049728491d4ea4f416c1eb013338682173259efa09/sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120", size = 2154547, upload-time = "2026-04-03T16:53:08.64Z" }, { url = "https://files.pythonhosted.org/packages/a2/bc/3494270da80811d08bcfa247404292428c4fe16294932bce5593f215cad9/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2", size = 3280782, upload-time = "2026-04-03T17:07:43.508Z" }, { url = "https://files.pythonhosted.org/packages/cd/f5/038741f5e747a5f6ea3e72487211579d8cbea5eb9827a9cbd61d0108c4bd/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3", size = 3297156, upload-time = "2026-04-03T17:12:27.697Z" }, { url = "https://files.pythonhosted.org/packages/88/50/a6af0ff9dc954b43a65ca9b5367334e45d99684c90a3d3413fc19a02d43c/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7", size = 3228832, upload-time = "2026-04-03T17:07:45.38Z" }, { url = "https://files.pythonhosted.org/packages/bc/d1/5f6bdad8de0bf546fc74370939621396515e0cdb9067402d6ba1b8afbe9a/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33", size = 3267000, upload-time = "2026-04-03T17:12:29.657Z" }, + { url = "https://files.pythonhosted.org/packages/f7/30/ad62227b4a9819a5e1c6abff77c0f614fa7c9326e5a3bdbee90f7139382b/sqlalchemy-2.0.49-cp313-cp313-win32.whl", hash = "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b", size = 2115641, upload-time = "2026-04-03T17:05:43.989Z" }, + { url = "https://files.pythonhosted.org/packages/17/3a/7215b1b7d6d49dc9a87211be44562077f5f04f9bb5a59552c1c8e2d98173/sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl", hash = "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148", size = 2141498, upload-time = "2026-04-03T17:05:45.7Z" }, { url = "https://files.pythonhosted.org/packages/28/4b/52a0cb2687a9cd1648252bb257be5a1ba2c2ded20ba695c65756a55a15a4/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518", size = 3560807, upload-time = "2026-04-03T16:58:31.666Z" }, { url = "https://files.pythonhosted.org/packages/8c/d8/fda95459204877eed0458550d6c7c64c98cc50c2d8d618026737de9ed41a/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d", size = 3527481, upload-time = "2026-04-03T17:06:00.155Z" }, { url = "https://files.pythonhosted.org/packages/ff/0a/2aac8b78ac6487240cf7afef8f203ca783e8796002dc0cf65c4ee99ff8bb/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0", size = 3468565, upload-time = "2026-04-03T16:58:33.414Z" }, { url = "https://files.pythonhosted.org/packages/a5/3d/ce71cfa82c50a373fd2148b3c870be05027155ce791dc9a5dcf439790b8b/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08", size = 3477769, upload-time = "2026-04-03T17:06:02.787Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e8/0a9f5c1f7c6f9ca480319bf57c2d7423f08d31445974167a27d14483c948/sqlalchemy-2.0.49-cp313-cp313t-win32.whl", hash = "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d", size = 2143319, upload-time = "2026-04-03T17:02:04.328Z" }, + { url = "https://files.pythonhosted.org/packages/0e/51/fb5240729fbec73006e137c4f7a7918ffd583ab08921e6ff81a999d6517a/sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl", hash = "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba", size = 2175104, upload-time = "2026-04-03T17:02:05.989Z" }, { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, ] @@ -5926,8 +7007,7 @@ version = "3.4.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "starlette", version = "1.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "starlette", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/2b/58abc2d1fd397e7dde08e947e05c884d8ef2f78d5e2588c17a12d42d6994/sse_starlette-3.4.4.tar.gz", hash = "sha256:07e0fa0460138baf25cdd5fb28683472c3995dc1642225191b3832d62526bcb0", size = 31819, upload-time = "2026-05-12T17:37:17.019Z" } wheels = [ @@ -5948,32 +7028,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] -[[package]] -name = "starlette" -version = "0.52.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "platform_machine == 'x86_64' and sys_platform == 'linux'", - "platform_machine == 'aarch64' and sys_platform == 'linux'", -] -dependencies = [ - { name = "anyio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, -] -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 = "starlette" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "platform_machine == 'x86_64' and sys_platform == 'linux'", - "platform_machine == 'aarch64' and sys_platform == 'linux'", -] dependencies = [ - { name = "anyio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-automodel') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-7-nemo-rl-mcore' and extra != 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'x86_64' and extra != 'extra-7-nemo-rl-automodel' and extra != 'extra-7-nemo-rl-fsdp' and extra != 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, + { name = "anyio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } wheels = [ @@ -6109,6 +7169,7 @@ version = "0.7.2" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb", size = 2356, upload-time = "2023-10-23T21:23:32.16Z" }, + { url = "https://files.pythonhosted.org/packages/b7/85/dabeaf902892922777492e1d253bb7e1264cadce3cea932f7ff599e53fea/tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60", size = 4823598, upload-time = "2023-10-23T21:23:33.714Z" }, { url = "https://files.pythonhosted.org/packages/73/c6/825dab04195756cf8ff2e12698f22513b3db2f64925bdd41671bfb33aaa5/tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530", size = 6590363, upload-time = "2023-10-23T21:23:35.583Z" }, ] @@ -6125,10 +7186,14 @@ dependencies = [ { name = "torch", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] wheels = [ + { url = "https://files.pythonhosted.org/packages/99/e8/ec3f0d5c1c96ff2ffe6eee27030aacf4c863a2d936a7e17fcd1b6cb63c3d/tensordict-0.12.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:853b6420c2458861434855453d75052b55887bcca2c4958fe9883813ba30a913", size = 890147, upload-time = "2026-05-22T00:09:29.602Z" }, { url = "https://files.pythonhosted.org/packages/4f/c3/ae214fbda9f2fe85bca76b272a7924d6a8b58990ba1b167028ae79bc0a85/tensordict-0.12.4-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3cfd1124b1931780b9e193a9fe7b37d50e5229dae4eaa715db5608c28803a710", size = 533774, upload-time = "2026-05-22T00:09:31.619Z" }, { url = "https://files.pythonhosted.org/packages/ed/3f/7e7f87da0a343ae234fc346653e812710c0c7823ceb1034b35652f7cbd90/tensordict-0.12.4-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:43e190dc05d217af3d27c207125db90ff5de1a7c5945aab34430a0d5cf81f7fd", size = 537544, upload-time = "2026-05-22T00:09:33.524Z" }, + { url = "https://files.pythonhosted.org/packages/77/0a/b765ae434ef1650b3f538fdc5ec979b2188a2c3e839a6dddb3b173f6d033/tensordict-0.12.4-cp313-cp313-win_amd64.whl", hash = "sha256:0d96da5907b7a5dbd10782a4166eb0e82a702e805b11f94a28bd629da61dff36", size = 586791, upload-time = "2026-05-22T00:09:35.659Z" }, + { url = "https://files.pythonhosted.org/packages/b3/84/c84936bdc4c2d1432f96d4e16f2521e196208332f985de6329bb8398d127/tensordict-0.12.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:a1e23296684e532650e236228c59fe0f4dd323d7c409c0798c18fd2791c1e252", size = 895573, upload-time = "2026-05-22T00:09:37.429Z" }, { url = "https://files.pythonhosted.org/packages/6d/b6/d574e2b758631563861d51cba4cc595d27a3965db3473a05ab268eead05b/tensordict-0.12.4-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:6e60888bc24990ead02d52f16fa607af8c01c92089ad767540eca88ade5fb49f", size = 535213, upload-time = "2026-05-22T00:09:39.561Z" }, { url = "https://files.pythonhosted.org/packages/13/a4/25c29e653878e58ed3cb111146e4dd8cdb4cfd4b6f66dd2080f94f8e78f4/tensordict-0.12.4-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:031c70d2101376e0fb8036b017c8271a27892c1b9ba6aea021c039c7535aac53", size = 539088, upload-time = "2026-05-22T00:09:41.377Z" }, + { url = "https://files.pythonhosted.org/packages/35/6f/c8107ea679a60e7584bc6d36b854879a33f5a990819e174a7ed653edb781/tensordict-0.12.4-cp313-cp313t-win_amd64.whl", hash = "sha256:a1320ea2ed9e0289209b0efc51b8bf2bca02cf5273fade3aec4f60a4ddfed61b", size = 597644, upload-time = "2026-05-22T00:09:42.922Z" }, ] [[package]] @@ -6150,14 +7215,20 @@ dependencies = [ ] 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/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]] @@ -6183,6 +7254,7 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e6/27/6e363f48f878389078e2899756b8fecc326388b585122fd7f8a86590dfab/tilelang-0.1.8.tar.gz", hash = "sha256:da967821698eb7a79a76d27fbe25e314a3273f2b12ba4833e981658139d0e6d9", size = 93247335, upload-time = "2026-02-16T14:03:28.706Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/de/17/10ab5c8ccc58783edcc5392ba653f4732702e44a72065224b3d7a4971852/tilelang-0.1.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:83654bff38448b6b26e143f150c928360619e91bf431289cf6cd74a4b31c7eba", size = 36016575, upload-time = "2026-02-16T14:02:54.054Z" }, { url = "https://files.pythonhosted.org/packages/5d/0b/96ba853aa9e4795020d183e0ca832e9e37d82d4f7f48896241323d1b5ece/tilelang-0.1.8-cp38-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a4018e581f55c852d98a42d3b4acf2dbcfb8b7d8b9156ba7c6b0ab61600a10c", size = 43477401, upload-time = "2026-02-16T14:03:02.879Z" }, { url = "https://files.pythonhosted.org/packages/e6/db/d130c8db9140bb21a2ef81a455614a4aeec3388088bf9af5df01ad0ba45d/tilelang-0.1.8-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:bcc2e28202cde516bdd59e1c25b7f6a139d1c52207d92576f4e711c6217e16ba", size = 40422585, upload-time = "2026-02-16T14:03:12.092Z" }, ] @@ -6211,6 +7283,7 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/56/70/5051f65821baa30a3d61fc48f8ba10c776490315e8c90f82559b92089756/tilelang-0.1.9.tar.gz", hash = "sha256:287f727c913bb648fcf6c1968809ba3390e55eeed257a5c6bb9a80bc05966af4", size = 93395292, upload-time = "2026-04-22T09:19:11.988Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/90/db/4dd76da8c8585c605639a21bc098d504e317fe324a72f01ce3c7370250b4/tilelang-0.1.9-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:00ed594fdeb229c5505b9ffa895c3c5daeb28641c78f783fa1f724cf1e08cecd", size = 36599020, upload-time = "2026-04-22T09:14:39.366Z" }, { url = "https://files.pythonhosted.org/packages/f7/8a/1cbeee79d62abaa02441c2d00621554e41aa62dbf3b94a4feb3867184b01/tilelang-0.1.9-cp38-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bbccfe9035aed775ffafb6dc25a5994504b24e2c5d95d0f39643edfafa7bf12", size = 45419374, upload-time = "2026-04-22T09:15:56.014Z" }, { url = "https://files.pythonhosted.org/packages/c6/a7/f4bfb86f87e107703146e703204cec2c0eae2492b633e0052b0ace3febb6/tilelang-0.1.9-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:77ab0ee2f40f66ea015b6b21426d482751e28cbc635ef9d1198cbd6502454a7c", size = 42110365, upload-time = "2026-04-22T09:17:18.292Z" }, ] @@ -6240,10 +7313,21 @@ dependencies = [ ] 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]] @@ -6270,6 +7354,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/49/7bae94729bfd7a3f331795251302f0b0c8e54a7ec25b3af5d5bfe133367c/tokenspeed_triton-3.7.10.post20260531-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b90ac41e7f15933797545ff1a9e803a9d8beb4ca9ba70f6d41a9e0fc26484f5c", size = 85888791, upload-time = "2026-05-31T01:29:25.584Z" }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + [[package]] name = "torch" version = "2.11.0+cu130" @@ -6293,8 +7386,10 @@ dependencies = [ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c3d60f79666b9101e3914a2e5dec2e81eac834e13cae0bcf59e94dc1a465f756", upload-time = "2026-04-27T20:04:49Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:554461b76f21211927c776056bcb0b00fb42972364794b686d768ebb0b586366", upload-time = "2026-04-27T20:05:21Z" }, + { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:339801f2163698a53c7fb3c91883e7f44331d22c34d45acfbce4eff71f2332fa", upload-time = "2026-04-27T20:06:44Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:a33905bc3e093b25d2b019181cf834f7f7d4c562739e13dd36a798ecb2e411b0", upload-time = "2026-04-27T20:08:23Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6fd10ed484eb695312ae829719888bb9f6c7f5e8503528e3e8ad1b98a45296c2", upload-time = "2026-04-27T20:08:56Z" }, + { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:21d2734fd02af45d19bb88c0ff2e86b238ce73f7bde6003ade7f1454ae299198", upload-time = "2026-04-27T20:10:20Z" }, ] [[package]] @@ -6306,8 +7401,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/37/de/921b6491efce5c389a5ef9bbed3d2d6660005840dae488124173180859ab/torch_c_dlpack_ext-0.1.5.tar.gz", hash = "sha256:d06f0357d575d22a168cc77acb9020fc4bae30968ceb6718a055dcbe92bacabe", size = 12913, upload-time = "2026-01-12T11:25:08.484Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/c6/65346a201d921b616731311fc9941f15137672b444cebdad702cb52ccee0/torch_c_dlpack_ext-0.1.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:74acea2ed395cadda63342845b9e9ee7cd4537846223dacfb4431b4610109265", size = 1993243, upload-time = "2026-01-12T11:24:51.079Z" }, { url = "https://files.pythonhosted.org/packages/fd/ec/faf10be09a5812b1c5ec9922b53fb5def5fc4080b81a653b9347bb169ebb/torch_c_dlpack_ext-0.1.5-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49f1e99d13c64e22dac0a34a1560e9e5a398a49a9fa81df83053e04fde6ec5bd", size = 443798, upload-time = "2026-01-12T11:24:52.754Z" }, { url = "https://files.pythonhosted.org/packages/2d/68/f434b48700f3e04f33882f54d8d3910327b935f55e14ec49da7d607bf470/torch_c_dlpack_ext-0.1.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:debe62e5ef93e631065d6b9f6e60d3d39bae6b89fa1b25d9523f40b3efbf8aba", size = 755004, upload-time = "2026-01-12T11:24:54.004Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/cc64e563f05ea99bd79bdb43f71f0f46452d3acd734da4843ede5fc73a35/torch_c_dlpack_ext-0.1.5-cp313-cp313-win_amd64.whl", hash = "sha256:30e3eab616dbc81dfdb7492aca557be551a9163ba9b585f97394a42b336b113a", size = 999126, upload-time = "2026-01-12T11:24:55.44Z" }, ] [[package]] @@ -6336,8 +7433,10 @@ source = { registry = "https://download.pytorch.org/whl/cu130" } wheels = [ { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:23498b01097648e304e78d6495a9f5bdce8441a802afc3025e2561973d74c025", upload-time = "2026-03-23T15:50:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e9c07cfdab691454092ff12d21dd1407a4bb8ad081d38f222cf6fcf6abcc18c8", upload-time = "2026-03-23T15:50:26Z" }, + { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:ce09a7b144b7982b46c8fe399cf5f91d43dda571e9d6ddba67e928567551f614", upload-time = "2026-03-23T15:50:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:f9b277a0d3b2ab4385778146b7e879716f36b6f2080f7190ec744e3383511791", upload-time = "2026-03-23T15:50:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:d07c4cbe4bec3e15bb18ba163058038f5f5fc1775c3061685c194439af4d2e9f", upload-time = "2026-03-23T15:50:26Z" }, + { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:b9dd151f06842ca77dc341aed94ea2f5d13a89e5027aa032a47198d073bcf3db", upload-time = "2026-03-23T15:50:26Z" }, ] [[package]] @@ -6345,8 +7444,10 @@ name = "torchcodec" version = "0.11.1" source = { registry = "https://pypi.org/simple" } wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/61/a8985a7561ef651e409deeac151a0ed5cef763db9577db5cc49c2f5eaab2/torchcodec-0.11.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:915fbe20068ec77486fbbeaf0c627c89c7376445f27d215b7489c0a03c64fd4c", size = 4289805, upload-time = "2026-04-14T18:24:59.124Z" }, { url = "https://files.pythonhosted.org/packages/7a/31/c4ec0304dd169a9b2b7fa0dd1d5d659d3cccc975b98ac88c498fe6dd7196/torchcodec-0.11.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3755de03c96afd37410cba68198225d11cd6431a32f2161a0019791a4a853305", size = 2399057, upload-time = "2026-04-14T18:25:00.782Z" }, { url = "https://files.pythonhosted.org/packages/5d/b2/85ad7a81f387e40983c21bc94da0c333974afb41f38c3a85d25875274187/torchcodec-0.11.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5eee69971cec1147a03b8a6b678b5dfbeff0b2c71ed7929e488391f9fbcd630c", size = 2332721, upload-time = "2026-04-14T18:25:02.518Z" }, + { url = "https://files.pythonhosted.org/packages/ad/ca/5c66f21d2a12039450e9dd4d9d7c480019dfbe9e8a87696a3c3a827c1e37/torchcodec-0.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:67b34e5733636588ebe0f15082bbb90a8ce1472ccb8bb1a656ec28958a208919", size = 1920990, upload-time = "2026-04-14T18:25:04.269Z" }, ] [[package]] @@ -6374,8 +7475,10 @@ dependencies = [ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3af2c699719cc0e2518bf317664200e5a987fb75a25b9b3bf3817a4796ddd64f", upload-time = "2026-03-23T15:36:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:441a98bed4fff1d54b8450499e377e1a605bec31f2ecb1a38a340f95dcc83897", upload-time = "2026-03-23T15:36:26Z" }, + { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:64de855465d6de60583e776889fad9412480f9f9e04fdd8d17ae96fa93864e9a", upload-time = "2026-04-09T23:21:54Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c3ac485da79552b4f579c525c826f7a63288b0d1cafc1201b16e1148bfdea69a", upload-time = "2026-03-23T15:36:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:110659ff38cd1d2ca0ac6e6a0f2c842fcb5fe739dfe65ff7456a12b2c4dce775", upload-time = "2026-03-23T15:36:26Z" }, + { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:a7e19c3ab5c6d8e3c9f8c6d427f6b8862dfb8227ea4a758ea7a709951daf2f0d", upload-time = "2026-04-09T23:21:55Z" }, ] [[package]] @@ -6552,11 +7655,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.15.0" +version = "4.16.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" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] [[package]] @@ -6618,6 +7721,8 @@ 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/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" }, @@ -7007,10 +8112,15 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/8e/31/fe53d06b75ef0a7f2f0ee5931a89f7aedc27d233840b1839616860fed256/wandb-0.27.0.tar.gz", hash = "sha256:579e75300173059f9334e1f513a79ef15f6d9ea5c74e20d695633648cdd02031", size = 41090732, upload-time = "2026-05-14T03:44:08.894Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/5e/2c199e70e636ecfd217cde0bc7469f4511e1d03d0685eb92bfdfce391430/wandb-0.27.0-py3-none-macosx_12_0_arm64.whl", hash = "sha256:c156be4851485f3c4160cb6eb2e8991b4cdeffbccefc5636d33cf5e254847365", size = 24886476, upload-time = "2026-05-14T03:43:27.569Z" }, + { url = "https://files.pythonhosted.org/packages/0b/cd/a617c871cd304a9804e56a7ec2ec2c65685bf0091a2b9f91910175a149e2/wandb-0.27.0-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:20179f38afb0158859a4141d29ac650d3fdbd0cf801a74ce25565c934f03776c", size = 26045779, upload-time = "2026-05-14T03:43:31.999Z" }, { url = "https://files.pythonhosted.org/packages/10/0a/d3f159a201530b84b72ca5f98c68d1f351c2d9a1864558ed76c811407fae/wandb-0.27.0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:626497d7975fa898d0a4a239da7a510483495ca3514510dbe75004a25963af4d", size = 25480764, upload-time = "2026-05-14T03:43:35.922Z" }, { url = "https://files.pythonhosted.org/packages/5f/6a/8721fcdf71d42639191040a77a585d2982402b1754700cb2ecfc2ca1470a/wandb-0.27.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:f772da7005cc26a2a32b729a16982a583dc68b3d493df6a09d0aa5c5ca5a2060", size = 27256204, upload-time = "2026-05-14T03:43:39.765Z" }, { url = "https://files.pythonhosted.org/packages/00/5e/279d167ba79fb7a8a43401c9f25efd0f6663ee9bd1eaf5a8578530198888/wandb-0.27.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:63acfc5b994e4a90e4a2fbdee6d45e664da3dd865bb1419942c8995c06c41cf1", size = 25647469, upload-time = "2026-05-14T03:43:44.817Z" }, { url = "https://files.pythonhosted.org/packages/94/51/a69ac59300e3c813939d0764348959ed2a21e14c668cb1cebcb04010da6a/wandb-0.27.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:17aae6e4a88cd05c00ea8f546220918e3ebb6f8c1c36b70ef04a5ac75f0d7160", size = 27599005, upload-time = "2026-05-14T03:43:50.926Z" }, + { url = "https://files.pythonhosted.org/packages/5f/40/bf510c8758727df020f83b717ebc1fcc1739ed7f6ae1796ebef60bf6f592/wandb-0.27.0-py3-none-win32.whl", hash = "sha256:0bd5659417e386bf6538b5e2ffe6885774c6197f0e4853bfed517d5b0db457f1", size = 25036164, upload-time = "2026-05-14T03:43:54.839Z" }, + { url = "https://files.pythonhosted.org/packages/54/ff/69f88e7d90c22b79bcb911143c13e59742ee192080b21015ff83a5a1f60a/wandb-0.27.0-py3-none-win_amd64.whl", hash = "sha256:89d584b73166eecee96fb446f18d0e45b1aa45aba6a3696296f3f06d7454516b", size = 25036170, upload-time = "2026-05-14T03:43:59.227Z" }, + { url = "https://files.pythonhosted.org/packages/f6/38/f7efd7a87297a55c7e9a331a1dbb5b19e54aeacc11fe6f43f8636a73987c/wandb-0.27.0-py3-none-win_arm64.whl", hash = "sha256:a6c129c311edf210a2b4f2f4acc557eff522628125f5f28ed27df19c16c07079", size = 22972710, upload-time = "2026-05-14T03:44:03.275Z" }, ] [[package]] @@ -7022,11 +8132,26 @@ dependencies = [ ] 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/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" }, @@ -7041,16 +8166,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" }, ] +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + [[package]] name = "websockets" version = "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/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/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] @@ -7084,14 +8223,28 @@ version = "2.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload-time = "2026-03-06T02:53:41.922Z" }, + { url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload-time = "2026-03-06T02:52:48.672Z" }, { url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload-time = "2026-03-06T02:54:14.013Z" }, { url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload-time = "2026-03-06T02:54:10.829Z" }, + { url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload-time = "2026-03-06T02:53:03.623Z" }, { url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload-time = "2026-03-06T02:53:45.844Z" }, + { url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload-time = "2026-03-06T02:54:46.356Z" }, { url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload-time = "2026-03-06T02:52:50.163Z" }, + { url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload-time = "2026-03-06T02:53:47.494Z" }, + { url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload-time = "2026-03-06T02:53:30.038Z" }, + { url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload-time = "2026-03-06T02:52:52.114Z" }, + { url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload-time = "2026-03-06T02:53:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload-time = "2026-03-06T02:54:33.452Z" }, { url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload-time = "2026-03-06T02:52:42.721Z" }, { url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload-time = "2026-03-06T02:54:25.441Z" }, + { url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload-time = "2026-03-06T02:53:57.456Z" }, { url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload-time = "2026-03-06T02:54:55.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload-time = "2026-03-06T02:54:24.092Z" }, { url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload-time = "2026-03-06T02:53:31.268Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload-time = "2026-03-06T02:54:15.391Z" }, + { url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload-time = "2026-03-06T02:54:41.943Z" }, + { url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload-time = "2026-03-06T02:54:48.093Z" }, { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] @@ -7100,7 +8253,7 @@ name = "wsproto" version = "1.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "h11", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "h11", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/79/12135bdf8b9c9367b8701c2c19a14c913c120b882d50b014ca0d38083c2c/wsproto-1.3.2.tar.gz", hash = "sha256:b86885dcf294e15204919950f666e06ffc6c7c114ca900b060d6e16293528294", size = 50116, upload-time = "2025-11-20T18:18:01.871Z" } wheels = [ @@ -7131,8 +8284,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/db/43/e5dfddb1d2a4fccf3e3a88f103e88698cdefc3182f4e169a359ffe1c1794/xgrammar-0.1.33.tar.gz", hash = "sha256:8dbe5fc3d76651ab1fac7a68fc2a118b885fa0ec7189927fb6e0dce0081aea99", size = 2398956, upload-time = "2026-03-27T10:16:36.582Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/b1/cce9f6d12b9de0db8b86401ea739fe79ac555f3da56e47faa5b874d41e42/xgrammar-0.1.33-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e5b46b922fb04fd1848198da5273ddc20f16693fba5871bac1837f1c90f59584", size = 22702353, upload-time = "2026-03-27T10:15:27.203Z" }, { url = "https://files.pythonhosted.org/packages/6b/55/4d186d4065f645a051be992919c51aaf96cfa8a32f7ecc8512a6e41f969f/xgrammar-0.1.33-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7eec984a20fd54d4c79536d99e2515bac54bd4e1380162fa047f5ff45bdf6d8", size = 42133430, upload-time = "2026-03-27T10:15:31.409Z" }, { url = "https://files.pythonhosted.org/packages/2b/ca/db765035b3bb1854bdb833c118e0f09dacc623ce5e867466d63610d635fa/xgrammar-0.1.33-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d705f62d91a3675997a81d09aa371c375d7793ce1021aff7b7ed5a92021c7379", size = 42206830, upload-time = "2026-03-27T10:15:35.574Z" }, + { url = "https://files.pythonhosted.org/packages/f5/17/635fc8933b35f24d0749fe177209abb5b526c99a2d098abb71c0e601f356/xgrammar-0.1.33-cp313-cp313-win_amd64.whl", hash = "sha256:2c626de8f503858efa28cab099cbb1719c4926af4250e8dea8efddfa2c6b6c91", size = 7222102, upload-time = "2026-03-27T10:15:38.617Z" }, ] [[package]] @@ -7141,17 +8296,49 @@ version = "3.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/24/2f/e183a1b407002f5af81822bee18b61cdb94b8670208ef34734d8d2b8ebe9/xxhash-3.7.0.tar.gz", hash = "sha256:6cc4eefbb542a5d6ffd6d70ea9c502957c925e800f998c5630ecc809d6702bae", size = 82022, upload-time = "2026-04-25T11:10:32.553Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ca/d5174b4c36d10f64d4ca7050563138c5a599efb01a765858ddefc9c1202a/xxhash-3.7.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:4b6d6b33f141158692bd4eafbb96edbc5aa0dabdb593a962db01a91983d4f8fa", size = 36813, upload-time = "2026-04-25T11:06:51.73Z" }, + { url = "https://files.pythonhosted.org/packages/41/d0/abc6c9d347ba1f1e1e1d98125d0881a0452c7f9a76a9dd03a7b5d2197f23/xxhash-3.7.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:845d347df254d6c619f616afa921331bada8614b8d373d58725c663ba97c3605", size = 35121, upload-time = "2026-04-25T11:06:53.048Z" }, { url = "https://files.pythonhosted.org/packages/bf/11/4cc834eb3d79f2f2b3a6ef7324195208bcdfbdcf7534d2b17267aa5f3a8f/xxhash-3.7.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:fddbbb69a6fff4f421e7a0d1fa28f894b20112e9e3fab306af451e2dfd0e459b", size = 29624, upload-time = "2026-04-25T11:06:54.311Z" }, { url = "https://files.pythonhosted.org/packages/23/83/e97d3e7b635fe73a1dfb1e91f805324dd6d930bb42041cbf18f183bc0b6d/xxhash-3.7.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:54876a4e45101cec2bf8f31a973cda073a23e2e108538dad224ba07f85f22487", size = 30638, upload-time = "2026-04-25T11:06:55.864Z" }, { url = "https://files.pythonhosted.org/packages/f4/40/d84951d80c35db1f4c40a29a64a8520eea5d56e764c603906b4fe763580f/xxhash-3.7.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:0c72fe9c7e3d6dfd7f1e21e224a877917fa09c465694ba4e06464b9511b65544", size = 33323, upload-time = "2026-04-25T11:06:57.336Z" }, + { url = "https://files.pythonhosted.org/packages/89/cc/c7dc6558d97e9ab023f663d69ab28b340ed9bf4d2d94f2c259cf896bb354/xxhash-3.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a6d73a830b17ef49bc04e00182bd839164c1b3c59c127cd7c54fcb10c7ed8ee8", size = 33362, upload-time = "2026-04-25T11:06:58.656Z" }, + { url = "https://files.pythonhosted.org/packages/2a/6e/46b84017b1301d54091430353d4ad5901654a3e0871649877a416f7f1644/xxhash-3.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c3b07cf3362086d8f126c6aecd8e5e9396ad8b2f2219ea7e49a8250c318acd", size = 30874, upload-time = "2026-04-25T11:06:59.834Z" }, + { url = "https://files.pythonhosted.org/packages/df/5e/8f9158e3ab906ad3fec51e09b5ea0093e769f12207bfa42a368ca204e7ab/xxhash-3.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:50e879ebbac351c81565ca108db766d7832f5b8b6a5b14b8c0151f7190028e3d", size = 194185, upload-time = "2026-04-25T11:07:01.658Z" }, { url = "https://files.pythonhosted.org/packages/f3/29/a804ded9f5d3d3758292678d23e7528b08fda7b7e750688d08b052322475/xxhash-3.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:921c14e93817842dd0dd9f372890a0f0c72e534650b6ab13c5be5cd0db11d47e", size = 213033, upload-time = "2026-04-25T11:07:03.606Z" }, + { url = "https://files.pythonhosted.org/packages/8b/91/1ce5a7d2fdc975267320e2c78fc1cecfe7ab735ccbcf6993ec5dd541cb2c/xxhash-3.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e64a7c9d7dfca3e0fafcbc5e455519090706a3e36e95d655cec3e04e79f95aaa", size = 236140, upload-time = "2026-04-25T11:07:05.396Z" }, + { url = "https://files.pythonhosted.org/packages/34/04/fd595a4fd8617b05fa27bd9b684ecb4985bfed27917848eea85d54036d06/xxhash-3.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2220af08163baf5fa36c2b8af079dc2cbe6e66ae061385267f9472362dfd53c6", size = 212291, upload-time = "2026-04-25T11:07:06.966Z" }, + { url = "https://files.pythonhosted.org/packages/03/fb/f1a379cbc372ae5b9f4ab36154c48a849ca6ebe3ac477067a57865bf3bc6/xxhash-3.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f14bb8b22a4a91325813e3d553b8963c10cf8c756cff65ee50c194431296c655", size = 445532, upload-time = "2026-04-25T11:07:08.525Z" }, { url = "https://files.pythonhosted.org/packages/65/59/172424b79f8cfd4b6d8a122b2193e6b8ad4b11f7159bb3b6f9b3191329bb/xxhash-3.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:496736f86a9bedaf64b0dc70e3539d0766df01c71ea22032698e88f3f04a1ce9", size = 193990, upload-time = "2026-04-25T11:07:10.315Z" }, + { url = "https://files.pythonhosted.org/packages/b9/19/aeac22161d953f139f07ba5586cb4a17c5b7b6dff985122803bb12933500/xxhash-3.7.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0ff71596bd79816975b3de7130ab1ff4541410285a3c084584eeb1c8239996fd", size = 284876, upload-time = "2026-04-25T11:07:12.15Z" }, { url = "https://files.pythonhosted.org/packages/77/d5/4fd0b59e7a02242953da05ff679fbb961b0a4368eac97a217e11dae110c1/xxhash-3.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1ad86695c19b1d46fe106925db3c7a37f16be37669dcf58dcc70a9dd6e324676", size = 210495, upload-time = "2026-04-25T11:07:13.952Z" }, + { url = "https://files.pythonhosted.org/packages/aa/fb/976a3165c728c7faf74aa1b5ab3cf6a85e6d731612894741840524c7d28c/xxhash-3.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:970f9f8c50961d639cbd0d988c96f80ddf66006de93641719282c4fe7a87c5e6", size = 241331, upload-time = "2026-04-25T11:07:15.557Z" }, + { url = "https://files.pythonhosted.org/packages/4a/2c/6763d5901d53ac9e6ba296e5717ae599025c9d268396e8faa8b4b0a8e0ac/xxhash-3.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5886ad85e9e347911783760a1d16cb6b393e8f9e3b52c982568226cb56927bdc", size = 198037, upload-time = "2026-04-25T11:07:17.563Z" }, + { url = "https://files.pythonhosted.org/packages/61/2b/876e722d533833f5f9a83473e6ba993e48745701096944e77bbecf29b2c3/xxhash-3.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6e934bbae1e0ec74e27d5f0d7f37ef547ce5ff9f0a7e63fb39e559fc99526734", size = 210744, upload-time = "2026-04-25T11:07:19.055Z" }, + { url = "https://files.pythonhosted.org/packages/21/e6/d7e7baef7ce24166b4668d3c48557bb35a23b92ecadcac7e7718d099ab69/xxhash-3.7.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:3b6b3d28228af044ebcded71c4a3dd86e1dbd7e2f4645bf40f7b5da65bb5fb5a", size = 275406, upload-time = "2026-04-25T11:07:20.908Z" }, + { url = "https://files.pythonhosted.org/packages/92/fe/198b3763b2e01ca908f2154969a2352ec99bda892b574a11a9a151c5ede4/xxhash-3.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:6be4d70d9ab76c9f324ead9c01af6ff52c324745ea0c3731682a0cf99720f1fe", size = 414125, upload-time = "2026-04-25T11:07:23.037Z" }, { url = "https://files.pythonhosted.org/packages/3a/6d/019a11affd5a5499137cacca53808659964785439855b5aa40dfd3412916/xxhash-3.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:151d7520838d4465461a0b7f4ae488b3b00de16183dd3214c1a6b14bf89d7fb6", size = 191555, upload-time = "2026-04-25T11:07:24.991Z" }, + { url = "https://files.pythonhosted.org/packages/76/21/b96d58568df2d01533244c3e0e5cbdd0c8b2b25c4bec4d72f19259a292d7/xxhash-3.7.0-cp313-cp313-win32.whl", hash = "sha256:d798c1e291bffb8e37b5bbe0dda77fc767cd19e89cadaf66e6ed5d0ff88c9fe6", size = 30668, upload-time = "2026-04-25T11:07:26.665Z" }, + { url = "https://files.pythonhosted.org/packages/99/57/d849a8d3afa1f8f4bc6a831cd89f49f9706fbbad94d2975d6140a171988c/xxhash-3.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:875811ba23c543b1a1c3143c926e43996eb27ebb8f52d3500744aa608c275aed", size = 31524, upload-time = "2026-04-25T11:07:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/81/52/bacc753e92dee78b058af8dcef0a50815f5f860986c664a92d75f965b6a5/xxhash-3.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:54a675cb300dda83d71daae2a599389d22db8021a0f8db0dd659e14626eb3ecc", size = 27768, upload-time = "2026-04-25T11:07:29.113Z" }, + { url = "https://files.pythonhosted.org/packages/1c/47/ddbd683b7fc7e592c1a8d9d65f73ce9ab513f082b3967eee2baf549b8fc6/xxhash-3.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a3b19a42111c4057c1547a4a1396a53961dca576a0f6b82bfa88a2d1561764b2", size = 33576, upload-time = "2026-04-25T11:07:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/07/f2/36d3310161db7f72efb4562aadde0ed429f1d0531782dd6345b12d2da527/xxhash-3.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8f4608a06e4d61b7a3425665a46d00e0579122e1a2fae97a0c52953a3aad9aa3", size = 31123, upload-time = "2026-04-25T11:07:31.989Z" }, + { url = "https://files.pythonhosted.org/packages/0d/3f/75937a5c69556ed213021e43cbedd84c8e0279d0d74e7d41a255d84ba4b1/xxhash-3.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ad37c7792479e49cf96c1ab25517d7003fe0d93687a772ba19a097d235bbe41e", size = 196491, upload-time = "2026-04-25T11:07:33.358Z" }, { url = "https://files.pythonhosted.org/packages/22/29/f10d7ff8c7a733d4403a43b9de18c8fabc005f98cec054644f04418659ee/xxhash-3.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc026e3b89d98e30a8288c95cb696e77d150b3f0fb7a51f73dcd49ee6b5577fa", size = 215793, upload-time = "2026-04-25T11:07:34.919Z" }, + { url = "https://files.pythonhosted.org/packages/8b/fd/778f60aa295f58907938f030a8b514611f391405614a525cccd2ffc00eb5/xxhash-3.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c9b31ab1f28b078a6a1ac1a54eb35e7d5390deddd56870d0be3a0a733d1c321c", size = 237993, upload-time = "2026-04-25T11:07:36.638Z" }, + { url = "https://files.pythonhosted.org/packages/70/f5/736db5de387b4a540e37a05b84b40dc58a1ce974bfd2b4e5754ce29b68c3/xxhash-3.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3bb5fd680c038fd5229e44e9c493782f90df9bef632fd0499d442374688ff70b", size = 214887, upload-time = "2026-04-25T11:07:38.564Z" }, + { url = "https://files.pythonhosted.org/packages/4d/aa/09a095f22fdb9a27fbb716841fbff52119721f9ca4261952d07a912f7839/xxhash-3.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:030c0fd688fce3569fbb49a2feefd4110cbb0b650186fb4610759ecfac677548", size = 448407, upload-time = "2026-04-25T11:07:40.552Z" }, { url = "https://files.pythonhosted.org/packages/74/8a/b745efeeca9e34a91c26fdc97ad8514c43d5a81ac78565cba80a1353870a/xxhash-3.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b1bde10324f4c31812ae0d0502e92d916ae8917cad7209353f122b8b8f610c3", size = 196119, upload-time = "2026-04-25T11:07:42.101Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5c/0cfceb024af90c191f665c7933b1f318ee234f4797858383bebd1881d52f/xxhash-3.7.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:503722d52a615f2604f5e7611de7d43878df010dc0053094ef91cb9a9ac3d987", size = 286751, upload-time = "2026-04-25T11:07:43.568Z" }, { url = "https://files.pythonhosted.org/packages/0b/0a/0793e405dc3cf8f4ebe2c1acec1e4e4608cd9e7e50ea691dabbc2a95ccbb/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c72500a3b6d6c30ebfc135035bcace9eb5884f2dc220804efcaaba43e9f611dd", size = 212961, upload-time = "2026-04-25T11:07:45.388Z" }, + { url = "https://files.pythonhosted.org/packages/0c/7e/721118ffc63bfff94aa565bcf2555a820f9f4bdb0f001e0d609bdfad70de/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:43475925a766d01ca8cd9a857fd87f3d50406983c8506a4c07c4df12adcc867f", size = 243703, upload-time = "2026-04-25T11:07:47.053Z" }, + { url = "https://files.pythonhosted.org/packages/6e/18/16f6267160488b8276fd3d449d425712512add292ba545c1b6946bfdb7dd/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8d09dfd2ab135b985daf868b594315ebe11ad86cd9fea46e6c69f19b28f7d25a", size = 200894, upload-time = "2026-04-25T11:07:48.657Z" }, + { url = "https://files.pythonhosted.org/packages/2d/94/80ba841287fd97e3e9cac1d228788c8ef623746f570404961eec748ecb5c/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c50269d0055ac1faecfd559886d2cbe4b730de236585aba0e873f9d9dadbe585", size = 213357, upload-time = "2026-04-25T11:07:50.257Z" }, + { url = "https://files.pythonhosted.org/packages/a1/7e/106d4067130c59f1e18a55ffadcd876d8c68534883a1e02685b29d3d8153/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:1910df4756a5ab58cfad8744fc2d0f23926e3efcc346ee76e87b974abab922f4", size = 277600, upload-time = "2026-04-25T11:07:51.745Z" }, + { url = "https://files.pythonhosted.org/packages/c5/86/a081dd30da71d720b2612a792bfd55e45fa9a07ac76a0507f60487473c25/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d006faf3b491957efcb433489be3c149efe4787b7063d5cddb8ddaefdc60e0c1", size = 416980, upload-time = "2026-04-25T11:07:53.504Z" }, { url = "https://files.pythonhosted.org/packages/35/29/1a95221a029a3c1293773869e1ab47b07cbbdd82444a42809e8c60156626/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:abb65b4e947e958f7b3b0d71db3ce447d1bc5f37f5eab871ce7223bda8768a04", size = 193840, upload-time = "2026-04-25T11:07:55.103Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/db909dd0823285de2286f67e10ee4d81e96ad35d7d8e964ecb07fccd8af9/xxhash-3.7.0-cp313-cp313t-win32.whl", hash = "sha256:178959906cb1716a1ce08e0d69c82886c70a15a6f2790fc084fdd146ca30cd49", size = 30966, upload-time = "2026-04-25T11:07:56.524Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ff/d705b15b22f21ee106adce239cb65d35067a158c630b240270f09b17c2e6/xxhash-3.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2524a1e20d4c231d13b50f7cf39e44265b055669a64a7a4b9a2a44faa03f19b6", size = 31784, upload-time = "2026-04-25T11:07:57.758Z" }, + { url = "https://files.pythonhosted.org/packages/a2/1f/b2cf83c3638fd0588e0b17f22e5a9400bdfb1a3e3755324ac0aee2250b88/xxhash-3.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:37d994d0ffe81ef087bb330d392caa809bb5853c77e22ea3f71db024a0543dba", size = 27932, upload-time = "2026-04-25T11:07:59.109Z" }, ] [[package]] @@ -7160,10 +8347,15 @@ version = "1.7.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9f/47/f7ec7744dff1104560d6276f951a8182f5b805e8d86ece591aebd0512845/yappi-1.7.6.tar.gz", hash = "sha256:c94281936af77c00c6ac2306a0e7f85a67e354d717120df85fcc5dfb9243d4dd", size = 62639, upload-time = "2026-03-17T22:31:40.928Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b0/9a10f3a22290b67e23f339318fd368c173547478e0896f89363fb9cf190b/yappi-1.7.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:072df6fa8b4cfb5159c261dd0df8e8b85de0adbadbc5e953e1183da193674bc4", size = 33299, upload-time = "2026-03-17T22:31:06.04Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ca/f36ccb82d7c96dee3858d26ed08e67de1767c309f285dbb2f76eceeaba48/yappi-1.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e4643d431656ec63e83455605ba29d1609d36b2fe14412e6939a223c323a7aee", size = 33193, upload-time = "2026-03-17T22:31:07.293Z" }, { url = "https://files.pythonhosted.org/packages/17/04/078db90359b39496f9192e375cd97831b138794cf456ad43bd8c7b65a4e3/yappi-1.7.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b27541c7f77ef2f76b2e0bb5da6dce5dc5fcdc7e500b4756e7a3e077d499ac25", size = 83096, upload-time = "2026-03-17T22:31:08.205Z" }, { url = "https://files.pythonhosted.org/packages/f0/52/24e214e5d4093e7b137fac95958afe289d1153ad35e6556be348c55a0b6a/yappi-1.7.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e100b6c36b922fc407078ed74f08b2463f46efc1fb440387eb493966e4ec434", size = 82639, upload-time = "2026-03-17T22:31:09.121Z" }, { url = "https://files.pythonhosted.org/packages/6d/d9/19b43be0e0f2a72518ec4907138614d4f98027839c10cd6b9b3a607cca2a/yappi-1.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5beecd15ff133c93fc505669754cb7caadd7fb19e87a71af133dfd1410e17aff", size = 80278, upload-time = "2026-03-17T22:31:10.039Z" }, { url = "https://files.pythonhosted.org/packages/68/9e/9fa404fee5eb4942ad36409b5d00e3783bd573982aa84f22c8a2646a7125/yappi-1.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3b5742d39c1ebe8909db0dec4a5b724a5a6167161864280021298f7ef4e76a1", size = 80337, upload-time = "2026-03-17T22:31:11.299Z" }, + { url = "https://files.pythonhosted.org/packages/92/2a/a42901c467259e10193c66a24bff410f041896ecdd3cb7b42dd515a54b2a/yappi-1.7.6-cp313-cp313-win32.whl", hash = "sha256:c9e3a92a04d9d6199fa0d157139beff1ca7eea7389e0e6b46b1353d8ffeec6a3", size = 32897, upload-time = "2026-03-17T22:31:12.219Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6c/dede83e0ca33701681acdb06854e492010257ae83bd9dda8e953983fab3a/yappi-1.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:95f9f326483d111b768f630a2d60689de7defff777f016b1f0dab9e93f36beb5", size = 35215, upload-time = "2026-03-17T22:31:13.084Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b0/dec448196d207b2e3b4e6b27dd74d0f1714b645af4f25cfe7dfd564ec14f/yappi-1.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:4981a243c5dbf105f6e1415197935ca36fde2b28adf26d2feceb95b5f1f77f06", size = 32861, upload-time = "2026-03-17T22:31:14.292Z" }, ] [[package]] @@ -7177,14 +8369,42 @@ dependencies = [ ] 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/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" }, ] @@ -7194,8 +8414,12 @@ version = "4.15.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8a/8e/0c8f17309549d2e5cde9a3ccefa6365437f1e7bafe71878eaf9478e47b18/z3_solver-4.15.4.0.tar.gz", hash = "sha256:928c29b58c4eb62106da51c1914f6a4a55d0441f8f48a81b9da07950434a8946", size = 5018600, upload-time = "2025-10-29T18:12:03.062Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/63/33/a3d5d2eaeb0f7b3174d57d405437eabb2075d4d50bd9ea0957696c435c7b/z3_solver-4.15.4.0-py3-none-macosx_13_0_arm64.whl", hash = "sha256:407e825cc9211f95ef46bdc8d151bf630e7ab2d62a21d24cd74c09cc5b73f3aa", size = 37052538, upload-time = "2025-10-29T18:11:46.233Z" }, + { url = "https://files.pythonhosted.org/packages/47/84/fd7ffac1551cd9f8d44fe41358f738be670fc4c24dfd514fab503f2cf3e7/z3_solver-4.15.4.0-py3-none-macosx_13_0_x86_64.whl", hash = "sha256:00bd10c5a6a5f6112d3a9a810d0799227e52f76caa860dafa5e00966bb47eb13", size = 39807925, upload-time = "2025-10-29T18:11:49.81Z" }, { url = "https://files.pythonhosted.org/packages/21/c9/bb51a96af0091324c81b803f16c49f719f9f6ea0b0bb52200f5c97ec4892/z3_solver-4.15.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e103a6f203f505b8b8b8e5c931cc407c95b61556512d4921c1ddc0b3f41b08e", size = 29268352, upload-time = "2025-10-29T18:11:53.032Z" }, { url = "https://files.pythonhosted.org/packages/bf/2e/0b49f7e4e53817cfb09a0f6585012b782dfe0b666e8abefcb4fac0570606/z3_solver-4.15.4.0-py3-none-manylinux_2_34_aarch64.whl", hash = "sha256:62c7e9cbdd711932301f29919ad9158de9b2f58b4d281dd259bbcd0a2f408ba1", size = 27226534, upload-time = "2025-10-29T18:11:55.59Z" }, + { url = "https://files.pythonhosted.org/packages/26/91/33de49538444d4aafbe47415c450c2f9abab1733e1226f276b496672f46c/z3_solver-4.15.4.0-py3-none-win32.whl", hash = "sha256:be3bc916545c96ffbf89e00d07104ff14f78336e55db069177a1bfbcc01b269d", size = 13191672, upload-time = "2025-10-29T18:11:58.424Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/a0b135e4419df475177ae78fc93c422430b0fd8875649486f9a5989772e6/z3_solver-4.15.4.0-py3-none-win_amd64.whl", hash = "sha256:00e35b02632ed085ea8199fb230f6015e6fc40554a6680c097bd5f060e827431", size = 16259597, upload-time = "2025-10-29T18:12:01.14Z" }, ] [[package]] From 591fa91b60eb0d995df2e9908f3a835b70fd8568 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Mon, 27 Jul 2026 23:09:10 -0700 Subject: [PATCH 32/44] =?UTF-8?q?feat(sc):=20S2=20token-capture=20worker?= =?UTF-8?q?=20hosting=20=E2=80=94=20install=5Fcapture,=20fan-outs,=20weigh?= =?UTF-8?q?t-version=20stamping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RL half of stage S2 (all dormant until the setup_token_capture fan-out, which S4 wires behind token_capture.enabled): - vllm_worker_async: install_token_capture (Gym CaptureHost seam), setup_token_capture fan-out target (in-worker DP client + TQTokenSink + the single install_capture call with the vLLM adapter; model owners only), _rollout_weight_version + set_rollout_weight_version. - vllm_generation: setup_token_capture / set_rollout_weight_version DP-leader fan-outs (async engine asserted). - single_controller: flag-gated set_rollout_weight_version rotation in _sync_weights beside RolloutManager.set_weight_version. - PY_EXECUTABLES.VLLM_GYM (--extra vllm --extra nemo_gym): capture-enabled worker env; verified nemo_gym capture core imports beside vllm 0.20.0. - pyrefly: tq_token_sink.py type-checked; nemo_gym.* replace-imports-with-any. - Gym submodule pin -> ccf9b6f6: S2 engine-blind capture core (staging/capture.py, fail-closed stage-then-respond ordering) + adapters/vllm.py (relocated replace_prefix_tokens splice, native id+logprob extraction) + 29 tests (75/75 green) + ruff format pass. - Tests: test_vllm_token_capture_hosting.py 6/6 (--nemo-gym-only). Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- 3rdparty/Gym-workspace/Gym | 2 +- ...m-gate-authoritative-implementation-log.md | 47 ++++- nemo_rl/algorithms/single_controller.py | 6 + nemo_rl/distributed/virtual_cluster.py | 4 + .../models/generation/vllm/vllm_generation.py | 31 ++++ .../generation/vllm/vllm_worker_async.py | 46 +++++ pyrefly.toml | 2 + .../test_vllm_token_capture_hosting.py | 173 ++++++++++++++++++ 8 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 tests/unit/models/generation/test_vllm_token_capture_hosting.py diff --git a/3rdparty/Gym-workspace/Gym b/3rdparty/Gym-workspace/Gym index 61fbb660a83..ccf9b6f63c7 160000 --- a/3rdparty/Gym-workspace/Gym +++ b/3rdparty/Gym-workspace/Gym @@ -1 +1 @@ -Subproject commit 61fbb660a83d0f30f3c45933d52426fc36216d08 +Subproject commit ccf9b6f63c776d2c96acbf18a26f79b99fd2d0c9 diff --git a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md index 0042bd17ae9..160f9e9e1b9 100644 --- a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md +++ b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md @@ -148,7 +148,52 @@ staging/ subpackage" (the post-review restructure; see Open TODOs). ## S2 — capture core + vLLM adapter + worker hosting -Status: not started (blocked on S1 sign-off) +Status: **code + tests complete (2026-07-28); awaiting user sign-off at the +S2 gate.** + +### Gym fork (submodule branch `tq-gate-capture`) + +One commit on top of the S1 pair: `51b8092e` "feat(token-id-capture): S2 +engine-blind capture core + vLLM adapter". + +| Item | Status | Notes | +|---|---|---| +| `staging/capture.py` | done | `RolloutTokenCapture.begin_call/complete_call` — engine-blind record + digest build; **fail-closed ordering**: staged coords exist only after `sink.stage` reports bytes durable, every capture failure (bad delta, sink rejection/exception, extraction error) degrades to `capture_failed` coords without breaking the served completion; weight version stamped at `begin_call` (generation-start semantics); streaming rejected (`StreamingUnsupportedError`); double-complete is a loud caller bug; `complete_call_from_response` drives the adapter; `install_capture` working body via the `CaptureHost` one-method seam (instance also returned) | +| `staging/protocols.py` | done | S1-frozen `install_capture` signature now delegates to the capture core (was `NotImplementedError`); same callable re-exported from `staging/__init__` | +| `adapters/vllm.py` | done | engine-specific only, **no vllm imports** (duck-typed payloads): `enter_prefix` via the worker's existing `required_prefix_token_ids` field; `replace_prefix_tokens` relocated **verbatim** from `nemo_rl/models/generation/vllm/vllm_worker_async.py`; native extraction off the final chat payload — message token fields or `choice.logprobs.content` `token_id:` entries (in-process; no second `/tokenize`); one-choice guard; `extract_prompt_ids` reads the hookup-attached engine prompt (vLLM's OpenAI response doesn't carry it) | +| tests | done | `tests/unit_tests/test_token_capture_s2_worker.py` — 29 tests: mock adapter + mock sink ordering matrix, install wiring, extraction shapes, splice goldens incl. the § 4.1-style retokenization-drift example; **75/75 green** (S2 + S1 primitives + #2124 base suite; the purity glob picked up `capture.py` automatically) | + +### NeMo-RL repo + +| Item | Status | Notes | +|---|---|---| +| `vllm_worker_async.py` hosting | done | `install_token_capture` (CaptureHost seam), `setup_token_capture(dp_cfg, staging_partition)` fan-out target (in-worker DP client + `TQTokenSink` + the single `install_capture` call with `VLLMCaptureAdapter`; model-owner ranks only), `_rollout_weight_version` attribute + `set_rollout_weight_version`. All dormant until the fan-out runs. | +| `vllm_generation.py` fan-outs | done | `setup_token_capture` (asserts async engine) + `set_rollout_weight_version`, standard `run_all_workers_single_data` DP-leader pattern | +| SC `_sync_weights` rotation | done | flag-gated `set_rollout_weight_version(self._trainer_version)` fan-out beside the existing `RolloutManager.set_weight_version` (§ 9.1 lists this under S4; pulled forward as it completes the S2 version-stamping story — disclosed) | +| `PY_EXECUTABLES.VLLM_GYM` | done | `--extra vllm --extra nemo_gym` worker env for capture-enabled runs (constant only; the flag-gated registry override for `VllmAsyncGenerationWorker` is S4 setup wiring) | +| pyrefly | done | `tq_token_sink.py` added to `project-includes`; `nemo_gym.*` added to `replace-imports-with-any` (editable finder hook unresolvable, same pattern as vllm/megatron) | +| Tests | done | `tests/unit/models/generation/test_vllm_token_capture_hosting.py` — 6 tests (`--nemo-gym-only`): install wiring w/ vLLM adapter, non-model-owner skip, live version stamping through the install closure into staged records, both fan-outs incl. async-engine guard | + +### S2 checks (carried from the S1 gate) + +- **Leaf package importable in the worker venv**: `uv run --locked --extra + vllm --extra nemo_gym` resolves and imports + `nemo_gym.token_id_capture.staging` + `adapters.vllm` beside vllm 0.20.0 + (the prebaked `--extra vllm`-only venv does *not* contain `nemo_gym` — + hence `VLLM_GYM`, switched in at setup only when capture is enabled). + +### Deviations / disclosures (for S2 sign-off) + +1. **`install_capture` returns the capture instance** (S1 signature said + `-> None`): additive; the `CaptureHost` seam remains the primary wiring. +2. **SC `_sync_weights` fan-out pulled forward from S4** (flag-gated, + dormant): completes per-call version stamping end-to-end in S2. +3. **`pyrefly.toml` edits** are active regardless of the flag (type-checker + config only; no runtime effect). +4. **Worker request-path integration deferred to S3** by design: the gate + owns the gate→worker context wire shape (serving rule § 3.3), so + `begin_call`/`complete_call` are not yet called from the HTTP handler — + S2 delivers the hosting seam, the capture core, and the adapter. ## S3 — Gym gate diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index e9020f87aec..eae553eae77 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -595,6 +595,12 @@ async def _sync_weights(self) -> None: print(f" _sync_weights: sync done in {elapsed:.3f}s", flush=True) self._rollout_manager.set_weight_version(self._trainer_version) + if self._master_config.token_capture.enabled: + # Rotate the version vLLM workers stamp on captured model calls + # (per-call tagging; group staleness = min over the group's calls). + await asyncio.to_thread( + self._gen.set_rollout_weight_version, self._trainer_version + ) self._rollout_permitted.set() async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: diff --git a/nemo_rl/distributed/virtual_cluster.py b/nemo_rl/distributed/virtual_cluster.py index 30dbc049943..2b0feccb7fe 100644 --- a/nemo_rl/distributed/virtual_cluster.py +++ b/nemo_rl/distributed/virtual_cluster.py @@ -73,6 +73,10 @@ class PY_EXECUTABLES: # Use NeMo-Gym dependencies NEMO_GYM = f"uv run --locked --extra nemo_gym --directory {git_root}" + # vLLM worker hosting Gym's token capture (token_capture.enabled): the + # worker imports nemo_gym's dependency-free capture core + vLLM adapter. + VLLM_GYM = f"uv run --locked --extra vllm --extra nemo_gym --directory {git_root}" + # Use NeMo-RL direct dependencies and SGLang. SGLANG = f"uv run --locked --extra sglang --directory {git_root}" diff --git a/nemo_rl/models/generation/vllm/vllm_generation.py b/nemo_rl/models/generation/vllm/vllm_generation.py index ce928cd9dba..5efd34c7341 100644 --- a/nemo_rl/models/generation/vllm/vllm_generation.py +++ b/nemo_rl/models/generation/vllm/vllm_generation.py @@ -526,6 +526,37 @@ def _post_init(self): results = ray.get(futures) return results + def setup_token_capture( + self, dp_cfg: dict[str, Any], staging_partition: str + ) -> None: + """Install gate-authoritative token capture in every DP-leader worker. + + Called once at setup when ``token_capture.enabled``; each async worker + builds its in-worker data-plane client + TQTokenSink and makes the + single Gym ``install_capture`` call (see + docs/design-docs/tq-gym-gate-authoritative.md § 9.1). + """ + assert self.cfg["vllm_cfg"]["async_engine"], ( + "token capture requires the async vLLM engine (the capture host " + "is the worker's in-process HTTP server)" + ) + futures = self.worker_group.run_all_workers_single_data( + "setup_token_capture", + dp_cfg=dp_cfg, + staging_partition=staging_partition, + run_rank_0_only_axes=["tensor_parallel", "pipeline_parallel"], + ) + ray.get(futures) + + def set_rollout_weight_version(self, version: int) -> None: + """Rotate the weight version workers stamp on captured model calls.""" + futures = self.worker_group.run_all_workers_single_data( + "set_rollout_weight_version", + version=version, + run_rank_0_only_axes=["tensor_parallel", "pipeline_parallel"], + ) + ray.get(futures) + def _get_raw_spec_counters(self) -> dict[str | tuple[str, int], float]: """Collect raw spec decode counters from workers.""" futures = self.worker_group.run_all_workers_single_data( diff --git a/nemo_rl/models/generation/vllm/vllm_worker_async.py b/nemo_rl/models/generation/vllm/vllm_worker_async.py index 591b929fbf4..2574015dbb1 100644 --- a/nemo_rl/models/generation/vllm/vllm_worker_async.py +++ b/nemo_rl/models/generation/vllm/vllm_worker_async.py @@ -195,6 +195,14 @@ def __init__( self.base_url = None self.http_server = None + # Gate-authoritative token capture (dormant until the + # setup_token_capture fan-out runs; see + # docs/design-docs/tq-gym-gate-authoritative.md § 9.1). The weight + # version is stamped per model call at begin_call time and rotated by + # the set_rollout_weight_version fan-out from the SC's _sync_weights. + self.token_capture = None + self._rollout_weight_version = 0 + super().__init__( config, bundle_indices, @@ -427,6 +435,44 @@ async def get_reserved_url(self) -> Optional[str]: async def report_dp_openai_server_base_url(self) -> Optional[str]: return self.base_url + def install_token_capture(self, capture: Any) -> None: + """Gym's ``install_capture`` seam (the ``CaptureHost`` contract).""" + self.token_capture = capture + + async def setup_token_capture( + self, dp_cfg: dict[str, Any], staging_partition: str + ) -> bool: + """Host gate-authoritative token capture in this worker. + + Fan-out target (token_capture.enabled only): builds the in-worker + data-plane client and TQTokenSink, then makes the single + ``install_capture`` call wiring Gym's engine-blind capture core + + vLLM adapter into this worker. Returns whether capture was installed + (False on non-model-owner ranks, which serve no HTTP). + """ + if not self.is_model_owner: + return False + # Deferred: nemo_gym is an optional extra absent in non-gym runs. + from nemo_gym.token_id_capture.adapters.vllm import VLLMCaptureAdapter + from nemo_gym.token_id_capture.staging import install_capture + + from nemo_rl.data_plane import build_data_plane_client + from nemo_rl.data_plane.tq_token_sink import TQTokenSink + + dp_client = build_data_plane_client(dp_cfg, bootstrap=False) + sink = TQTokenSink(dp_client, staging_partition=staging_partition) + install_capture( + self, + sink=sink, + weight_version_fn=lambda: self._rollout_weight_version, + adapter=VLLMCaptureAdapter(), + ) + return True + + async def set_rollout_weight_version(self, version: int) -> None: + """Rotate the weight version stamped on subsequent captured calls.""" + self._rollout_weight_version = int(version) + # ruff: noqa def _setup_vllm_openai_api_server(self, app: FastAPI) -> FastAPI: from copy import deepcopy diff --git a/pyrefly.toml b/pyrefly.toml index 760945fc0c9..28683742c87 100644 --- a/pyrefly.toml +++ b/pyrefly.toml @@ -8,6 +8,7 @@ replace-imports-with-any = [ "transformers.*", "vllm.*", "math_verify.*", + "nemo_gym.*", "sympy.*", "torchdata.*", "nemo.*", @@ -111,6 +112,7 @@ project-includes = [ "nemo_rl/data_plane/observability.py", "nemo_rl/data_plane/preshard.py", "nemo_rl/data_plane/schema.py", + "nemo_rl/data_plane/tq_token_sink.py", "nemo_rl/data_plane/worker_mixin.py", "nemo_rl/distributed/__init__.py", "nemo_rl/distributed/collectives.py", diff --git a/tests/unit/models/generation/test_vllm_token_capture_hosting.py b/tests/unit/models/generation/test_vllm_token_capture_hosting.py new file mode 100644 index 00000000000..28edb951409 --- /dev/null +++ b/tests/unit/models/generation/test_vllm_token_capture_hosting.py @@ -0,0 +1,173 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""S2 worker hosting: install_capture wiring, fan-outs, version stamping. + +Marked nemo_gym (run with ``--nemo-gym-only``): the hosting seam imports +Gym's capture core. No engine or GPU is needed — the worker methods are +driven unbound against light fakes, and the VllmGeneration fan-outs against +a mock worker group. +""" + +from __future__ import annotations + +import asyncio +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest + +nemo_gym = pytest.importorskip("nemo_gym.token_id_capture.staging") + +from nemo_gym.token_id_capture.staging.capture import ( # noqa: E402 + RolloutTokenCapture, +) +from nemo_gym.token_id_capture.staging.records import ( # noqa: E402 + StagedCallRecord, + StageResult, +) + +from nemo_rl.models.generation.vllm.vllm_generation import VllmGeneration # noqa: E402 +from nemo_rl.models.generation.vllm.vllm_worker_async import ( # noqa: E402 + VllmAsyncGenerationWorkerImpl, +) + +pytestmark = pytest.mark.nemo_gym + + +class _MemorySink: + def __init__(self) -> None: + self.records: list[StagedCallRecord] = [] + + def stage(self, record: StagedCallRecord) -> StageResult: + self.records.append(record) + return StageResult(ok=True, staging_key=record.staging_key) + + +def _fake_worker(*, is_model_owner: bool = True) -> SimpleNamespace: + """The attribute surface setup_token_capture touches, minus the engine.""" + worker = SimpleNamespace( + is_model_owner=is_model_owner, + token_capture=None, + _rollout_weight_version=0, + ) + worker.install_token_capture = lambda capture: setattr( + worker, "token_capture", capture + ) + return worker + + +def test_setup_token_capture_installs_capture_with_vllm_adapter(monkeypatch): + sink = _MemorySink() + monkeypatch.setattr( + "nemo_rl.data_plane.build_data_plane_client", + lambda dp_cfg, bootstrap: MagicMock(name="dp_client"), + ) + monkeypatch.setattr( + "nemo_rl.data_plane.tq_token_sink.TQTokenSink", + lambda dp_client, *, staging_partition: sink, + ) + worker = _fake_worker() + + installed = asyncio.run( + VllmAsyncGenerationWorkerImpl.setup_token_capture( + worker, dp_cfg={"backend": "simple"}, staging_partition="rollout_staging" + ) + ) + + assert installed is True + assert isinstance(worker.token_capture, RolloutTokenCapture) + assert worker.token_capture.adapter is not None + # The adapter is the vLLM one (prefix ids enter via the worker's field). + payload = worker.token_capture.adapter.enter_prefix({}, [1, 2]) + assert payload["required_prefix_token_ids"] == [1, 2] + + +def test_setup_token_capture_skips_non_model_owners(monkeypatch): + worker = _fake_worker(is_model_owner=False) + installed = asyncio.run( + VllmAsyncGenerationWorkerImpl.setup_token_capture( + worker, dp_cfg={}, staging_partition="rollout_staging" + ) + ) + assert installed is False + assert worker.token_capture is None + + +def test_weight_version_is_stamped_from_worker_state(monkeypatch): + """The install closure reads _rollout_weight_version live: a + set_rollout_weight_version between calls changes the stamp.""" + sink = _MemorySink() + monkeypatch.setattr( + "nemo_rl.data_plane.build_data_plane_client", + lambda dp_cfg, bootstrap: MagicMock(), + ) + monkeypatch.setattr( + "nemo_rl.data_plane.tq_token_sink.TQTokenSink", + lambda dp_client, *, staging_partition: sink, + ) + worker = _fake_worker() + asyncio.run( + VllmAsyncGenerationWorkerImpl.setup_token_capture( + worker, dp_cfg={}, staging_partition="rollout_staging" + ) + ) + + asyncio.run(VllmAsyncGenerationWorkerImpl.set_rollout_weight_version(worker, 4)) + first = worker.token_capture.begin_call(rollout_id="r", call_id="c1", mode="text") + asyncio.run(VllmAsyncGenerationWorkerImpl.set_rollout_weight_version(worker, 5)) + second = worker.token_capture.begin_call(rollout_id="r", call_id="c2", mode="text") + + assert (first.weight_version, second.weight_version) == (4, 5) + + coords = worker.token_capture.complete_call( + first, prompt_token_ids=[1], generated_token_ids=[2], generated_logprobs=[-0.1] + ) + assert coords.weight_version == 4 + assert sink.records[0].weight_version == 4 + + +def _generation_with_mock_group(*, async_engine: bool = True) -> VllmGeneration: + gen = object.__new__(VllmGeneration) + gen.cfg = {"vllm_cfg": {"async_engine": async_engine}} + gen.worker_group = MagicMock() + gen.worker_group.run_all_workers_single_data.return_value = [] + return gen + + +def test_generation_setup_token_capture_fans_out(monkeypatch): + gen = _generation_with_mock_group() + gen.setup_token_capture({"backend": "simple"}, "rollout_staging") + gen.worker_group.run_all_workers_single_data.assert_called_once_with( + "setup_token_capture", + dp_cfg={"backend": "simple"}, + staging_partition="rollout_staging", + run_rank_0_only_axes=["tensor_parallel", "pipeline_parallel"], + ) + + +def test_generation_setup_token_capture_requires_async_engine(): + gen = _generation_with_mock_group(async_engine=False) + with pytest.raises(AssertionError, match="async vLLM engine"): + gen.setup_token_capture({}, "rollout_staging") + + +def test_generation_set_rollout_weight_version_fans_out(): + gen = _generation_with_mock_group() + gen.set_rollout_weight_version(7) + gen.worker_group.run_all_workers_single_data.assert_called_once_with( + "set_rollout_weight_version", + version=7, + run_rank_0_only_axes=["tensor_parallel", "pipeline_parallel"], + ) From 7f89d7ada9b1072deece84d683d1918eac908a05 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 00:03:50 -0700 Subject: [PATCH 33/44] =?UTF-8?q?feat(sc):=20S3=20token-capture=20?= =?UTF-8?q?=E2=80=94=20Gym=20gate=20(submodule=20pin=2005986b04)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gym fork gains the gate: lineage hosting in the vLLM model server (memory token buffer, marker resolve + history fingerprint, § 3.3 serving rule, exact prefix serving, coords ingestion as the authoritative commit, token-free receipts, TTLs), register/seal/fail control routes + RolloutControlClient, and marker plumbing through the responses converter. All dormant behind token_capture_gate.enabled=false; Gym suite 1507 green. Also records the S1 functional pin-bump evidence in the implementation log (grpo_dp_single_controller.sh and grpo_async_gym_single_controller.sh both PASS flag-off after NRL_FORCE_REBUILD_VENVS=true; stale prebaked container venvs documented as environmental). Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- 3rdparty/Gym-workspace/Gym | 2 +- ...m-gate-authoritative-implementation-log.md | 81 ++++++++++++++++++- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/3rdparty/Gym-workspace/Gym b/3rdparty/Gym-workspace/Gym index ccf9b6f63c7..05986b04e6b 160000 --- a/3rdparty/Gym-workspace/Gym +++ b/3rdparty/Gym-workspace/Gym @@ -1 +1 @@ -Subproject commit ccf9b6f63c776d2c96acbf18a26f79b99fd2d0c9 +Subproject commit 05986b04e6ba6db9d6fe0c61ad9da979e615e3a5 diff --git a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md index 160f9e9e1b9..cdbdec96019 100644 --- a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md +++ b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md @@ -143,8 +143,24 @@ staging/ subpackage" (the post-review restructure; see Open TODOs). `grpo.seed`. Flagged for the user at the gate (fixable as a test-fixture patch, but left untouched to keep the stage diff clean). -- SC functional tests (`L1_Functional_Tests_SingleController.sh`, 8×H100) - with the flag off: planned as pin-bump regression evidence at the gate. +- SC functional tests (flag off, dev node GPUs) as pin-bump regression + evidence: + - `tests/functional/grpo_dp_single_controller.sh` (Qwen3-0.6B, 2 GPUs, + Megatron + async vLLM + TQ): **PASS** (2026-07-28) — all 5 metric + checks green (`gen_kl_error` max 6.0e-4 < 2e-3; probs-ratio clamps + exactly 1.0). Caveat: required `NRL_FORCE_REBUILD_VENVS=true` — the + container's prebaked `/opt/ray_venvs` are stale vs the branch lock + (Ray 2.54.0 vs 2.55.1; `nvidia-resiliency-ext` 0.6.0.dev33 < 0.6.0's + minimum). Both mismatches pre-date the S1 uv.lock regen (Ray 2.55.1 + was already pinned at branch HEAD); environmental, not this work. + - `tests/functional/grpo_async_gym_single_controller.sh` (SC + NeMo-Gym + workplace-assistant, Qwen3-0.6B, 2 GPUs, 10 steps): **PASS** + (2026-07-28) — metric checks green (`median(gen_kl_error)`=0.041 < 1.3; + `max(reward)`=0.5 > 0). Same caveat: needs `NRL_FORCE_REBUILD_VENVS=true` + on this node (stale prebaked NemoGym-actor venv, Ray 2.54.0). + **This is the flag-off pin-bump evidence for the Gym submodule move + `610a08ab` → the tq-gate-capture branch** (disclosure 1): the legacy + token-echo path through the new pin trains correctly. ## S2 — capture core + vLLM adapter + worker hosting @@ -181,6 +197,13 @@ engine-blind capture core + vLLM adapter". `nemo_gym.token_id_capture.staging` + `adapters.vllm` beside vllm 0.20.0 (the prebaked `--extra vllm`-only venv does *not* contain `nemo_gym` — hence `VLLM_GYM`, switched in at setup only when capture is enabled). +- **Splice relocation equivalence** (scratchpad + `validate_splice_relocation.py`): Gym's `replace_prefix_tokens` produces + byte-identical output to the RL worker's `_replace_prefix_tokens` on the + S1-gate templates — Qwen3-0.6B (retokenization_differs=True, the + ``-strip drift case) and Qwen2.5-1.5B-Instruct — plus the + no-prefix path. The RL original stays in place until S3 hosts the Gym + copy on the request path, so both existing callers are untouched. ### Deviations / disclosures (for S2 sign-off) @@ -197,7 +220,59 @@ engine-blind capture core + vLLM adapter". ## S3 — Gym gate -Status: not started (blocked on S2 sign-off) +Status: **code + tests complete (2026-07-28); awaiting user sign-off at the +S3 gate.** (S2 sign-off was given verbally — "In case S2 is done can you +start S3" — with the S2 gate summary below still standing for review.) + +### Gym fork (submodule branch `tq-gate-capture`) + +One commit: `05986b04` "feat(token-id-capture): S3 gate — lineage hosting, +prefix serving, marker plumbing, control plane". No rebase was needed — the +fork already sits on #2124's head (`32b555f04`), and its 20-test base suite +stays green. + +| Item | Status | Notes | +|---|---|---| +| `token_id_capture/memory_store.py` | done | `MemoryRolloutTokenBuffer` — per-rollout **delta forest** (parent-linked deltas; forks share prefixes through the chain instead of duplicating cumulative sequences; O(total committed tokens)); create-only register, chain-walk `cumulative_ids`, `drop` at seal/fail/TTL. Ids only, never logprobs | +| `token_id_capture/gate.py` | done | `RolloutCaptureGate` hosting the S1 `lineage.py` machine — **no new lineage logic**: registration (create-only), `find_marker` (deepest `ng_call_id` names the parent; sub-agent forks resolve to interior nodes), `message_fingerprint` (normalized role / text content with `` stripped / tool-call name+args / tool linkage; capture carriers and token fields excluded — pinned by conformance tests), the § 3.3 serving rule in `prepare_call` (token-in only for known marker + matching fingerprint; else text-mode new root with `fallback_reason`), `ingest_coords` = authoritative commit (buffer extend + fingerprint record + marker release; `capture_failed` poisons and releases nothing), `seal_rollout` → token-free receipt + full state drop, `fail_rollout` / `expire_stale` TTL, § 8 metrics counters. `RolloutGateConfig` (enabled=False) | +| `token_id_capture/control_routes.py` | done | `PUT /ng-control/rollouts/{id}` (create-only, 409 on dup), `POST .../seal` (receipt; 404 after drop), `POST .../fail` (idempotent), `GET /ng-control/metrics`; `RolloutControlClient` for the framework side (aiohttp via `server_utils.request`, deferred import) | +| `openai_utils.py` | done | `CallMarkerMixin` / `CallMarkerTypedDictMixin` + `WithMarker` variants of the five response items, the assistant chat param, and the chat response message, mirrored on the `ForTraining` pattern; unions extended | +| `responses_converter.py` | done | outbound: marker attaches to the last content-bearing output item (`RESPONSES_TO_MARKER`, same carrier as the token arrays); inbound: an echoed marker item survives conversion onto the flushed assistant chat message. Both directions are presence-driven — no config, dormant when no gate mints markers | +| `responses_api_models/vllm_model/app.py` | done | flag-gated gate hosting: `prepare_call` after `_preprocess_chat_completion_create_params` (both sides of the fingerprint see one normalization pipeline); exact prefix into the worker's existing `required_prefix_token_ids` splice seam + `ng_capture` call context; engine logprob/token-id request fields set gate-side (worker extracts natively; the gate strips `logprobs` from the response so they never reach the agent); coords popped off the response = the commit — a **missing-coords response is committed as `capture_failed`** (rollout poisoned loudly, completion still served); marker attach; sha256(rollout_id) → client **affinity** (stateless, no map to leak); control routes installed in `setup_webserver`; backend errors/context-length shortcuts fail the admitted call (no marker → no children); setup-time `ValueError` when gate + legacy token echo are both enabled | +| tests | done | `tests/unit_tests/test_token_capture_s3_gate.py` — 21 tests: **all 4 S1 golden call sequences replayed through the gate produce receipts byte-identical to the direct `RolloutLineage` drive** (fixture→gate call-id renaming only); fallback matrix (marker stripped / history edited / unknown marker / reasoning-strip fingerprint stability); duplicate + wrong-rollout coords rejection; capture-failed poisoning; seal-drops-state + TTL; buffer fork prefixes; control-route round trips; converter marker echo round trip. `responses_api_models/vllm_model/tests/test_token_capture_gate_app.py` — 5 server e2e tests over HTTP with a fake capture-enabled worker (register → 2-turn conversation with exact prefix service and prev_len chaining → seal receipt; missing-coords poisoning; edited-history two-root fallback; dormant server exposes nothing; config guard). **Full Gym suite 1507 passed / 30 skipped** incl. all prior capture suites and the 72 existing vllm_model app tests | + +### Deviations / disclosures (for S3 sign-off) + +1. **Buffer interface**: the in-memory buffer exposes a delta-chain interface + rather than implementing #2124's `TokenCaptureStore` (JSONL `TokenEntry` + append/read) — prefix serving needs parent-linked deltas, not per-call + full snapshots. The JSONL store remains untouched as the debug/persistence + backend (H1). +2. **Marker carriers are presence-driven, not config-gated**, in the + converter and typed models: markers can only exist when a gate minted + them, so the legacy path is byte-identical with the flag off (union + additions verified against the full 1507-test suite). +3. **Rollout affinity is a stable hash** (sha256(rollout_id) mod clients), + not the prototype's sticky map — stateless, so nothing leaks when + rollouts outlive sessions. Design § 9.2 asked for "rollout affinity in + `_resolve_client`"; the mechanism choice is disclosed here. +4. **Gate-side engine fields**: in gate mode the gate (not + `return_token_id_information`) sets `logprobs=True, top_logprobs=0, + return_tokens_as_token_ids=True` on the worker request — the S2 adapter's + extraction shapes need them until native extraction is wired deeper + (worker-side stripping + coords attach is the S4 RL hookup). +5. **`fail_rollout` control route is idempotent** (returns `failed: false` + after seal/TTL instead of erroring) — a cancelled dispatch double-fail + must not crash teardown (§ 7 cleanup). +6. Functional-test side effect: `ng_prepare_data` rewrote + `workplace_assistant` metrics JSONs in the submodule working tree during + the flag-off evidence run; reverted, not committed. + +Not in S3 (lands in S4 with the RL wiring): NeMo-RL's use of +`RolloutControlClient` (register/seal/fail from `environments/nemo_gym.py`), +rollout-id minting + metadata plumbing from the SC, worker-side coords +attach/strip (the serving hookup that pairs with S2's `RolloutTokenCapture`), +receipts through `run_rollouts`, and the finalizer. ## S4 — receipts, finalizer, SC integration From bab7dd6532ef70ccf31e501b9ee6eee25eb3ea09 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 00:08:20 -0700 Subject: [PATCH 34/44] docs(sc): record S3-pin flag-off functional evidence in the capture log Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- .../tq-gym-gate-authoritative-implementation-log.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md index cdbdec96019..259b46d463b 100644 --- a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md +++ b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md @@ -266,7 +266,16 @@ stays green. must not crash teardown (§ 7 cleanup). 6. Functional-test side effect: `ng_prepare_data` rewrote `workplace_assistant` metrics JSONs in the submodule working tree during - the flag-off evidence run; reverted, not committed. + the flag-off evidence runs; reverted, not committed. + +### Regression evidence (flag off, S3 pin) + +- `tests/functional/grpo_async_gym_single_controller.sh` re-run against the + S3 pin (`05986b04`, gate code present but `token_capture_gate.enabled` + defaulting false): **PASS** (2026-07-28) — `median(gen_kl_error)`=0.038 + < 1.3, `max(reward)`=0.5 > 0. The legacy token-echo path through the + edited `app.py`/converter is behaviorally unchanged. +- Full Gym unit suite at the S3 commit: 1507 passed / 30 skipped. Not in S3 (lands in S4 with the RL wiring): NeMo-RL's use of `RolloutControlClient` (register/seal/fail from `environments/nemo_gym.py`), From 6b32665ca579d9aca923f4844f6357bd472d9739 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 12:03:35 -0700 Subject: [PATCH 35/44] =?UTF-8?q?feat(sc):=20S4=20token-capture=20?= =?UTF-8?q?=E2=80=94=20receipts,=20blackbox=20finalizer,=20SC=20integratio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NeMo-RL side of the gate-authoritative pipeline (no Gym fork changes): blackbox_finalizer (receipt → TQ fetch → § 5 verification → linearize → always-N publish with placeholders, group_min/max_wv, group-drop and mixed-wv policies), worker request-path capture (begin/finish/abort around chat completions; coords ride ng_commit_coords, logprobs stripped), receipt-mode run_rollouts + gate control plane in the NemoGym env (register/seal/fail, NaN-retry hard error), capture dispatch in RolloutManager (rollout-id minting {group_id}_g{i}, commit_finalized, failure-path aborts), validity-aware GRPO baseline via sample_mask, setup wiring (MVP-matrix validation, VLLM_GYM registry override, setup_token_capture + weight-version fan-outs, finalizer threading), exemplar YAML token_capture block. All dormant behind token_capture.enabled=false; flag-off regression 522 passed. Gate evidence (2×H100, 10 steps, capture enabled): both metric checks PASS — median gen_kl_error 0.0375 (flag-off run: 0.038), max reward 0.5, global_valid_seqs=8.0 every step (zero placeholders trained); cancelled dispatches exercised the § 7 failure path loudly and leaked nothing. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- ...m-gate-authoritative-implementation-log.md | 82 +++- .../grpo_math_1B_single_controller.yaml | 23 ++ nemo_rl/algorithms/advantage_estimator.py | 9 +- nemo_rl/algorithms/single_controller.py | 3 + .../single_controller_utils/setup.py | 69 ++++ nemo_rl/environments/nemo_gym.py | 145 ++++++- nemo_rl/experience/blackbox_finalizer.py | 366 ++++++++++++++++++ nemo_rl/experience/rollout_manager.py | 179 ++++++++- .../generation/vllm/vllm_worker_async.py | 81 +++- pyrefly.toml | 1 + .../algorithms/test_advantage_validity.py | 54 +++ .../data_plane/test_blackbox_finalizer.py | 247 ++++++++++++ tests/unit/experience/test_rollout_manager.py | 173 ++++++++- .../test_vllm_token_capture_hosting.py | 139 +++++++ 14 files changed, 1544 insertions(+), 27 deletions(-) create mode 100644 nemo_rl/experience/blackbox_finalizer.py create mode 100644 tests/unit/algorithms/test_advantage_validity.py create mode 100644 tests/unit/data_plane/test_blackbox_finalizer.py diff --git a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md index 259b46d463b..803392722f3 100644 --- a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md +++ b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md @@ -285,7 +285,87 @@ receipts through `run_rollouts`, and the finalizer. ## S4 — receipts, finalizer, SC integration -Status: not started (blocked on S3 sign-off) +Status: **complete (2026-07-28) — code, unit tests, and live capture-enabled +gate evidence (below) all green; awaiting user sign-off at the combined +S2–S4 gate.** (S3 sign-off pending — the user asked to "Finish S4"; S2–S4 +are presented together at the gate.) + +All NeMo-RL-side; no Gym fork changes in this stage. + +| Item | Status | Notes | +|---|---|---| +| `nemo_rl/experience/blackbox_finalizer.py` (new) | done | orchestration only: `finalize_rollout` — receipt → `TQTokenSource.fetch` by manifest keys → § 5 verification (digest recompute over fetched float32 values, mask ∈ {0,1}, finite logprobs, `prev_len + delta_len == cum_len`, weight-version tag equality) → Gym `linearize(main_chain_only, terminal_hint)`; `finalize_group` — always N rows (`{group_id}_g{i}` == the gate-registered rollout ids), placeholders (`sample_mask=0`, `prompt_ids_for_adv` from a valid sibling), `group_min_wv`/`group_max_wv` (fallback wv for all-placeholder groups), `min_valid_fraction_per_group` group drop, `mixed_weight_version_policy` allow/reject, publish via `pack_payload` → `put_samples`, then clear the group's staged rows (finalizer is the staging partition's only reader) | +| worker request path (`vllm_worker_async.py`) | done | the S2/S3 pairing: `_begin_request_capture` at `preprocess_chat` (both render paths — post-splice ids in token-in mode, full render in text mode), `_finish_request_capture` in the chat endpoint (stage → coords ride `ng_commit_coords`; logprobs stripped so the worker→gate hop is token-light § 3.2), `_abort_request_capture` on every endpoint error path; `ng_capture` field on `NeMoRLChatCompletionRequest` | +| `environments/nemo_gym.py` | done | `token_capture` on `NemoGymConfig`; `_spinup` injects the gate config through the `policy_model.responses_api_models.vllm_model` global-config override block (`token_capture_gate.enabled=true`, `return_token_id_information=false`) and **hard-errors unless `rollout_max_attempts_to_avoid_lp_nan == 1`** (NaN-retry would re-register create-only ids); control-plane helpers (`register_rollouts`/`fail_rollouts`/`gate_metrics` + seal) via Gym's `ServerClient` resolving the `policy_model` server by name; receipt-mode `run_rollouts` registers before dispatch, seals per completed row, and returns token-free results (the legacy token walk + contiguity assert never runs — the gate owns that guarantee) | +| `experience/rollout_manager.py` | done | capture dispatch `_generate_and_finalize`: mints `{group_id}_g{i}` (sample ids == rollout ids), reserves the slot with them, threads them into row `metadata.ng_rollout_id`, finalizes via `asyncio.to_thread`, commits via `commit_finalized`; failure path aborts the slot **and** best-effort-fails the gate registrations; receipt-mode `Completion` (token-free; receipt in `env_extras`); receipt-derived token metrics; receipts excluded from the wandb table | +| `algorithms/advantage_estimator.py` + SC | done | `GRPOAdvantageEstimator.compute_advantage(valid_mask=...)` replaces the hardwired `torch.ones_like` in `calculate_baseline_and_std_per_prompt`; the SC advantage pump passes `sample_mask` (validity folded, no new train field); other estimators absorb the kwarg | +| `single_controller_utils/setup.py` | done | MVP-matrix validation (requires NeMo-Gym path + vllm + async engine, loud `ValueError`/`NotImplementedError`); `VLLM_GYM` registry override for `VllmAsyncGenerationWorker` **before** generation builds; `setup_token_capture` + `set_rollout_weight_version(0)` fan-outs after partition pre-registration; `BlackboxFinalizer` built and threaded into `RolloutManager`; gate config into `spinup_nemo_gym_actor` | +| exemplar YAML | done | documented `token_capture` block in `examples/configs/grpo_math_1B_single_controller.yaml` (defaults live on `TokenCaptureConfig`); config-validation suite green | +| pyrefly | done | `blackbox_finalizer.py` added to `project-includes`; no new errors | + +### Tests (all green) + +- `tests/unit/data_plane/test_blackbox_finalizer.py` — 5 tests vs a **live TQ + simple backend**: the S1 worked-example golden row reproduces byte-exact + through staging + finalize; the rejection matrix (missing receipt, + poisoned, empty manifest, identity mismatch, missing rows, digest + corruption); mixed-wv allow/reject; N-row publish with sibling-prompt + placeholder + staging cleanup; `min_valid_fraction_per_group` drop. +- `tests/unit/models/generation/test_vllm_token_capture_hosting.py` — +4 + request-path tests (10 total): begin→finish round trip (stage before + coords, logprobs stripped, state drained), token-in `prev_len` chaining, + no-op off the capture path, abort semantics. +- `tests/unit/experience/test_rollout_manager.py` — +3 receipt-mode tests + (13 total): id minting/threading end-to-end, `commit_finalized` carry, + dropped-group abort, failed-dispatch abort + gate `fail_rollouts`. +- `tests/unit/algorithms/test_advantage_validity.py` — 2 tests: invalid rows + excluded from the per-prompt baseline; `None` keeps legacy behavior. +- Flag-off regression: `tests/unit/single_controller/` + + `tests/unit/experience/` + `test_config_validation.py`: **522 passed** + (same two pre-existing branch-HEAD failures excluded, documented at S1). + +### Deviations / disclosures (for S4 sign-off) + +1. **Finalizer runs in the dispatch task** via `asyncio.to_thread` (design's + MVP placement); finalize latency rides the rollout dispatch, not the + train pump. +2. **Gate config injection** uses the `policy_model` global-config override + block (the mechanism env yamls already use) instead of new + `global_config.py` keys — no Gym-side config change needed. +3. **Legacy test fixtures updated**: `_make_manager`/hand-built managers in + `test_rollout_manager.py` gained the new `_finalizer`/`_env_handles` + attributes (the legacy `run_rollout` impl call stays byte-identical — + verified by the pre-existing flow tests). +4. **`gate_metrics` control endpoint** is exposed via the NemoGym actor but + not yet logged per train step (receipt-derived rollout metrics + + `finalize/*` metrics land in `rollout_metrics`); wiring + `token_in_rate` into the SC logger is S5 work with the § 8 metrics pass. +5. **`commit_finalized` staging_keys are empty** by design: the finalizer + clears staged rows right after publish, so eviction has nothing extra to + clear (the design's staging-aware `remove` remains for abnormal paths). + +### Gate evidence (2-GPU capture-enabled run) + +- `grpo_async_gym_single_controller.sh ++token_capture.enabled=true` + (2026-07-28, dev node, 2×H100, 10 steps): **PASS** — both metric checks + green: `median(gen_kl_error)`=0.0375 < 1.3 (statistically identical to + the flag-off S3-pin run's 0.038 — the gate→worker→TQ→finalizer path + reproduces legacy token fidelity), `max(reward)`=0.5 > 0. Every train + step ran with `global_valid_seqs=8.0` — all rows finalizer-verified + valid, zero placeholder rows trained. +- Observed failure-path exercise (loud, handled, § 7 semantics): 3 of the + ~40 dispatched groups were cancelled by the SC mid-flight; their agents' + in-flight calls then hit the gate after `fail_rollouts` dropped the + create-only registrations → `UnknownRolloutError` from + `gate.prepare_call` → HTTP 500 to the (already-dead) rollout, and one + group's late `seal` correctly got 404 and was absorbed by the + `seal(...) failed` warning path. No leaks into training: none of these + groups produced rows, and all trained steps were full-valid. +- Environment caveat (unchanged from S1): first attempt failed on the + node's stale prebaked `/opt/ray_venvs` (vllm 0.17.1/Ray 2.54.0 vs the + lock's 0.20.0/2.55.1 → `ModuleNotFoundError: + vllm.entrypoints.serve.render`); the recorded PASS is the rerun with + `NRL_FORCE_REBUILD_VENVS=true`. ## S5 — verification diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml index b20eb9dc9fa..9ab82b44413 100644 --- a/examples/configs/grpo_math_1B_single_controller.yaml +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -351,6 +351,29 @@ async_rl: # False: enforces per-weight-version dispatch quota. over_sampling: true +# Gate-authoritative token capture (token-in/token-out via NeMo-Gym; see +# docs/design-docs/tq-gym-gate-authoritative.md). Dormant by default: with +# enabled=false every legacy codepath behaves exactly as before. Requires the +# NeMo-Gym rollout path (env.should_use_nemo_gym=true) with the async vLLM +# backend; defaults live on TokenCaptureConfig +# (nemo_rl/algorithms/single_controller_utils/config.py). +token_capture: + enabled: false + # TQ partition holding per-call staged token deltas (finalizer-cleared). + staging_partition: "rollout_staging" + # continue: a failed worker-side stage poisons the rollout (placeholder row); + # abort: fails the whole rollout at the gate. + on_capture_failure: "continue" + # allow: train groups whose calls span a refit (staleness = group's oldest + # call version); reject: placeholder such rollouts. + mixed_weight_version_policy: "allow" + # Drop the whole group when fewer than this fraction of its rollouts + # produced valid rows (null keeps every group). + min_valid_fraction_per_group: null + # Gate-side cleanup backstops (seconds). + registration_ttl_s: 3600.0 + staging_ttl_s: 3600.0 + cluster: gpus_per_node: 2 num_nodes: 1 diff --git a/nemo_rl/algorithms/advantage_estimator.py b/nemo_rl/algorithms/advantage_estimator.py index 59fd0f1ed01..faa40c3617f 100644 --- a/nemo_rl/algorithms/advantage_estimator.py +++ b/nemo_rl/algorithms/advantage_estimator.py @@ -50,7 +50,7 @@ def __init__(self, estimator_config: dict, loss_config: ClippedPGLossConfig): self.use_leave_one_out_baseline = estimator_config["use_leave_one_out_baseline"] self.normalize_rewards = estimator_config["normalize_rewards"] - def compute_advantage(self, prompt_ids, rewards, mask, **kwargs): + def compute_advantage(self, prompt_ids, rewards, mask, valid_mask=None, **kwargs): """Compute GRPO advantages. Args: @@ -58,6 +58,11 @@ def compute_advantage(self, prompt_ids, rewards, mask, **kwargs): rewards: Tensor of shape [batch_size] containing reward for each sample. mask: Response token mask of shape [batch_size, seq_len], 1 for valid response tokens, 0 for padding. Used only for expanding advantages to token-level shape. + valid_mask: Optional tensor of shape [batch_size], 1.0 for samples whose + reward should participate in the per-prompt baseline/std. Token-capture + placeholder rows carry 0.0 (their sample_mask already excludes them + from the loss; excluding them here keeps siblings' baselines unbiased). + None keeps the legacy all-valid behavior. **kwargs: Additional arguments (unused). Returns: @@ -66,7 +71,7 @@ def compute_advantage(self, prompt_ids, rewards, mask, **kwargs): baseline, std = calculate_baseline_and_std_per_prompt( prompt_ids, rewards, - torch.ones_like(rewards), + torch.ones_like(rewards) if valid_mask is None else valid_mask.float(), leave_one_out_baseline=self.use_leave_one_out_baseline, ) advantages = (rewards - baseline).unsqueeze(-1) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index eae553eae77..33dceeb0004 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -659,6 +659,9 @@ async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: rewards=rewards, mask=mask, repeated_batch=repeated_batch, + # Real validity (token-capture placeholders carry sample_mask 0) + # instead of the hardwired all-ones — § 9.1, advantage_estimator. + valid_mask=sample_mask, **kwargs, ) self._step_log_dict["masked_advantages"].append( diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index 12fac785c6e..9782bfcf7ea 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -276,6 +276,37 @@ def setup_single_controller( "data.use_multiple_dataloader=True yet." ) + # Token capture: validate the MVP matrix loudly at setup (§ 6, § 10) and + # give capture-enabled vLLM workers a venv that carries nemo_gym (the + # worker hosts Gym's capture core + adapter in-process). + token_capture_cfg = master_config.token_capture + if token_capture_cfg.enabled: + if not _should_use_nemo_gym(master_config): + raise ValueError( + "token_capture.enabled requires the NeMo-Gym rollout path " + "(env.should_use_nemo_gym=true) — the gate lives in Gym's " + "policy model server" + ) + if generation_config["backend"] != "vllm": + raise NotImplementedError( + "token_capture.enabled supports the vllm backend only; got " + f"{generation_config['backend']!r}" + ) + if not generation_config["vllm_cfg"]["async_engine"]: + raise ValueError( + "token_capture.enabled requires " + "policy.generation.vllm_cfg.async_engine=true (the capture " + "host is the worker's in-process HTTP server)" + ) + from nemo_rl.distributed.ray_actor_environment_registry import ( + ACTOR_ENVIRONMENT_REGISTRY, + ) + from nemo_rl.distributed.virtual_cluster import PY_EXECUTABLES + + ACTOR_ENVIRONMENT_REGISTRY[ + "nemo_rl.models.generation.vllm.vllm_worker_async.VllmAsyncGenerationWorker" + ] = PY_EXECUTABLES.VLLM_GYM + set_seed(grpo_config["seed"]) # ========================== @@ -342,6 +373,12 @@ def setup_single_controller( env_configs=master_config.env, base_urls=generation.dp_openai_server_base_urls, model_name=generation_config["model_name"], + # Gate config rides into Gym's policy model server (§ 9.1). + token_capture=( + master_config.token_capture.model_dump() + if master_config.token_capture.enabled + else None + ), ) # ========================== @@ -376,6 +413,25 @@ def setup_single_controller( num_samples=num_rollout_samples, consumer_tasks=["finalize"], ) + # Host Gym's capture core in every vLLM DP leader (in-worker DP + # client + TQTokenSink + the single install_capture call), and give + # workers the initial weight version to stamp on captured calls. + try: + generation.setup_token_capture(dp_cfg, token_capture_cfg.staging_partition) + except Exception as error: + if "No module named 'nemo_gym'" in str(error): + # Worker venvs are cached by actor class name + # (nemo_rl/utils/venvs.py), so a venv prebuilt before token + # capture predates the nemo_gym extra and is reused as-is. + raise RuntimeError( + "token_capture.enabled requires nemo_gym inside the vLLM " + "worker venv, but the cached worker venv predates it. " + "Rebuild worker venvs (NRL_FORCE_REBUILD_VENVS=true) or " + "delete $NEMO_RL_VENV_DIR/nemo_rl.models.generation.vllm." + "vllm_worker_async.VllmAsyncGenerationWorker and rerun." + ) from error + raise + generation.set_rollout_weight_version(0) backend = generation_config["backend"] weight_synchronizer = create_weight_synchronizer( @@ -403,6 +459,18 @@ def setup_single_controller( token_capture_cfg.staging_partition if token_capture_cfg.enabled else None ), ) + finalizer = None + if token_capture_cfg.enabled: + from nemo_rl.experience.blackbox_finalizer import BlackboxFinalizer + + finalizer = BlackboxFinalizer( + dp_client, + partition_id=partition_id, + staging_partition=token_capture_cfg.staging_partition, + pad_token_id=pad_id, + mixed_weight_version_policy=token_capture_cfg.mixed_weight_version_policy, + min_valid_fraction_per_group=token_capture_cfg.min_valid_fraction_per_group, + ) rollout_manager = RolloutManager( tokenizer=tokenizer, env_handles=env_handles, @@ -413,6 +481,7 @@ def setup_single_controller( generation_config=generation_config, use_nemo_gym=use_nemo_gym, tq_buffer=tq_buffer, + finalizer=finalizer, ) return SingleControllerBundle( diff --git a/nemo_rl/environments/nemo_gym.py b/nemo_rl/environments/nemo_gym.py index 15f511da88b..fd984cb885d 100644 --- a/nemo_rl/environments/nemo_gym.py +++ b/nemo_rl/environments/nemo_gym.py @@ -80,6 +80,17 @@ class NemoGymConfig(TypedDict): thinking_tags: NotRequired[ List[str] | None ] # Thinking tags to check for malformed usage + # Gate-authoritative token capture (token_capture.enabled): the dumped + # TokenCaptureConfig. Turns on the gate in Gym's policy model server, + # switches run_rollouts to receipt mode, and adds the register/seal/fail + # control-plane helpers. None/absent = legacy token-echo path. + token_capture: NotRequired[Dict[str, Any] | None] + + +# Gym control-plane server name (the model server hosting the gate) and the +# metadata key rollout ids ride on (defined in Gym's token_id_capture.gate). +_POLICY_SERVER_NAME = "policy_model" +_NG_ROLLOUT_ID_METADATA_KEY = "ng_rollout_id" def _detect_invalid_tool_call_and_malformed_thinking( @@ -235,6 +246,35 @@ def _spinup(self) -> None: "`rollout_max_attempts_to_avoid_lp_nan` must be at least 1" ) + # Gate-authoritative token capture: turn on the gate in the policy + # model server (via the policy_model global-config override block the + # env yamls already use) and disable the legacy token echo. Receipt + # mode is incompatible with re-dispatching a batch under the same + # rollout ids, so the NaN retry must be exactly 1 (create-only + # registration would fail the retry loudly anyway; fail at setup). + token_capture = self.cfg.get("token_capture") or None + self._token_capture_enabled = bool( + token_capture and token_capture.get("enabled") + ) + self._server_client = None + if self._token_capture_enabled: + if self.rollout_max_attempts_to_avoid_lp_nan != 1: + raise ValueError( + "token_capture.enabled requires " + "rollout_max_attempts_to_avoid_lp_nan == 1: a NaN retry " + "would re-register create-only rollout ids at the gate" + ) + policy_overrides = ( + initial_global_config_dict.setdefault("policy_model", {}) + .setdefault("responses_api_models", {}) + .setdefault("vllm_model", {}) + ) + policy_overrides["return_token_id_information"] = False + policy_overrides["token_capture_gate"] = { + "enabled": True, + "registration_ttl_s": token_capture["registration_ttl_s"], + } + self.rh = RunHelper() self.rh.start( global_config_dict_parser_config=GlobalConfigDictParserConfig( @@ -252,6 +292,51 @@ def _spinup(self) -> None: ) self.rch = RolloutCollectionHelper() + # ── gate control plane (token-capture mode) ───────────────────────────── + + def _control_client(self): + """Gym ServerClient resolving servers by name from the head server.""" + if self._server_client is None: + from nemo_gym.server_utils import ServerClient + + self._server_client = ServerClient.load_from_global_config( + self.head_server_config + ) + return self._server_client + + async def _control(self, method: str, path: str, **kwargs: Any) -> dict: + response = await self._control_client().request( + server_name=_POLICY_SERVER_NAME, url_path=path, method=method, **kwargs + ) + if response.status != 200: + raise RuntimeError( + f"gate control call {method} {path} failed: " + f"HTTP {response.status} {await response.text()}" + ) + return await response.json() + + async def register_rollouts(self, rollout_ids: list[str]) -> None: + """Create-only registration before dispatch (§ 3.1).""" + for rollout_id in rollout_ids: + await self._control("PUT", f"/ng-control/rollouts/{rollout_id}") + + async def fail_rollouts(self, rollout_ids: list[str], *, reason: str) -> None: + """Best-effort gate cleanup for a cancelled/failed dispatch (§ 7).""" + for rollout_id in rollout_ids: + try: + await self._control( + "POST", + f"/ng-control/rollouts/{rollout_id}/fail", + json={"reason": reason}, + ) + except (RuntimeError, OSError) as error: + # The registration TTL is the backstop when the gate is + # unreachable during teardown. + print(f"fail_rollout({rollout_id}) failed: {error}", flush=True) + + async def gate_metrics(self) -> dict: + return await self._control("GET", "/ng-control/metrics") + async def run_rollouts( self, nemo_gym_examples: list[dict], @@ -260,6 +345,17 @@ async def run_rollouts( ) -> list[dict]: timer = Timer() + if self._token_capture_enabled: + # Receipt mode: register the gate-registered ids riding each + # row's metadata before dispatch; seal at completion. + rollout_ids = [ + example["responses_create_params"]["metadata"][ + _NG_ROLLOUT_ID_METADATA_KEY + ] + for example in nemo_gym_examples + ] + await self.register_rollouts(rollout_ids) + timer.start("_run_rollouts_total") max_attempts, trial = self.rollout_max_attempts_to_avoid_lp_nan, 0 while trial < max_attempts: @@ -275,9 +371,14 @@ async def run_rollouts( nemo_gym_row, nemo_gym_result = await task with timer.time(label=f"{timer_prefix}/postprocess_results"): - nemo_rl_result = self._postprocess_nemo_gym_to_nemo_rl_result( - nemo_gym_result, tokenizer - ) + if self._token_capture_enabled: + nemo_rl_result = await self._postprocess_receipt_mode( + nemo_gym_row, nemo_gym_result + ) + else: + nemo_rl_result = self._postprocess_nemo_gym_to_nemo_rl_result( + nemo_gym_result, tokenizer + ) nemo_rl_rowidxs.append(nemo_gym_row["_rowidx"]) nemo_rl_results.append(nemo_rl_result) @@ -316,6 +417,42 @@ async def run_rollouts( return nemo_rl_results, timing_metrics + async def _postprocess_receipt_mode( + self, nemo_gym_row: dict, nemo_gym_result: dict + ) -> dict: + """Seal the rollout and return a token-free result (§ 9.1). + + The legacy token walk (and its contiguity assert) does not run: the + gate owns lineage now, output items carry no token arrays, and the + canonical row is rebuilt by the finalizer from staged deltas. The + Ray return carries only the receipt (~100 B/call) beside the + agent-level result. + """ + assert isinstance(nemo_gym_result, dict), ( + f"Hit a non-successful response when querying NeMo Gym for rollouts: {nemo_gym_result}" + ) + rollout_id = nemo_gym_row["responses_create_params"]["metadata"][ + _NG_ROLLOUT_ID_METADATA_KEY + ] + try: + receipt = await self._control( + "POST", + f"/ng-control/rollouts/{rollout_id}/seal", + json={"reward": float(nemo_gym_result.get("reward") or 0.0)}, + ) + except (RuntimeError, OSError) as error: + # An unsealable rollout finalizes as a placeholder; the gate's + # registration TTL sweeps its state. + print(f"seal({rollout_id}) failed: {error}", flush=True) + receipt = None + return { + "message_log": [], + "input_message_log": [], + "full_result": nemo_gym_result, + "rollout_id": rollout_id, + "receipt": receipt, + } + def _postprocess_nemo_gym_to_nemo_rl_result( self, nemo_gym_result: dict, tokenizer: PreTrainedTokenizerBase ) -> dict: @@ -454,6 +591,7 @@ def spinup_nemo_gym_actor( env_configs: dict[str, Any], base_urls: list[Optional[str]], model_name: str, + token_capture: Optional[dict[str, Any]] = None, ) -> Any: """Spin up the NeMo-Gym actor against the given generation server URLs. @@ -485,6 +623,7 @@ def spinup_nemo_gym_actor( invalid_tool_call_patterns=invalid_tool_call_patterns, thinking_tags=thinking_tags, initial_global_config_dict=nemo_gym_dict, + token_capture=token_capture, ) nemo_gym_opts: dict[str, Any] = {} diff --git a/nemo_rl/experience/blackbox_finalizer.py b/nemo_rl/experience/blackbox_finalizer.py new file mode 100644 index 00000000000..04a48863a47 --- /dev/null +++ b/nemo_rl/experience/blackbox_finalizer.py @@ -0,0 +1,366 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""Blackbox finalization: token-free receipts + staged deltas -> canonical rows. + +Orchestration only (docs/design-docs/tq-gym-gate-authoritative.md § 5, § 9.1): +per rollout, fetch the staged rows the receipt manifest names through the +``TokenSource``, re-verify them (digest recomputation over fetched values, +shape/mask/finite-logprob checks, length chaining, weight-version tag +equality), then delegate semantics to Gym's pure ``linearize`` +(``main_chain_only`` + ``terminal_hint``). Any rejection becomes a masked +placeholder row — the group always publishes exactly N rows so GRPO group +shape survives; validity folds into ``sample_mask`` (no new train field) and +placeholders copy ``prompt_ids_for_adv`` from a valid sibling so per-prompt +baselines stay well-formed. + +The finalizer is the only reader of the staging partition and clears a +group's staged rows after its canonical rows are durably published. +""" + +from __future__ import annotations + +import math +from dataclasses import dataclass, field +from typing import Any, Optional + +import torch + +from nemo_rl.data_plane import KVBatchMeta +from nemo_rl.data_plane.tq_token_sink import TQTokenSink, TQTokenSource +from nemo_rl.experience.payload import pack_payload + + +@dataclass(frozen=True) +class FinalizedRollout: + """One rollout's canonical row, or its rejection.""" + + rollout_id: str + valid: bool + rejection_reason: Optional[str] + token_ids: list[int] + token_mask: list[float] + logprobs: list[float] + prompt_len: int + reward: float + staging_keys: list[str] + min_wv: Optional[int] = None + max_wv: Optional[int] = None + + +@dataclass +class FinalizedGroup: + """What ``finalize_group`` hands back for ``commit_finalized``.""" + + meta: Optional[KVBatchMeta] + group_min_wv: int + group_max_wv: int + staging_keys: list[str] + metrics: dict[str, float] = field(default_factory=dict) + # True when min_valid_fraction_per_group rejected the whole group; the + # caller aborts the slot instead of committing it. + dropped: bool = False + + +class BlackboxFinalizer: + """Receipts -> verified rows -> N-row publish, off the generation hot path.""" + + def __init__( + self, + dp_client: Any, + *, + partition_id: str, + staging_partition: str, + pad_token_id: int, + mixed_weight_version_policy: str, + min_valid_fraction_per_group: Optional[float], + ) -> None: + self._dp_client = dp_client + self._partition_id = partition_id + self._pad_token_id = int(pad_token_id) + self._mixed_weight_version_policy = mixed_weight_version_policy + self._min_valid_fraction = min_valid_fraction_per_group + self._source = TQTokenSource(dp_client, staging_partition=staging_partition) + # The sink's clear() is the staging-partition delete; no staging + # writes happen here. + self._staging = TQTokenSink(dp_client, staging_partition=staging_partition) + + # ── per rollout ───────────────────────────────────────────────────────── + + def finalize_rollout( + self, rollout_id: str, receipt: Optional[dict[str, Any]], *, reward: float + ) -> FinalizedRollout: + """Verify one receipt against its staged rows and linearize the main chain. + + Never raises for rollout-level problems: every rejection returns an + invalid row whose reason feeds the metrics; the group publisher + substitutes a placeholder. + """ + # Deferred: nemo_gym is an optional extra absent in non-gym runs. + from nemo_gym.token_id_capture.staging.digest import compute_staging_digest + from nemo_gym.token_id_capture.staging.rebuild import RebuildError, linearize + from nemo_gym.token_id_capture.staging.records import RolloutReceipt + + def rejected(reason: str, staging_keys: list[str]) -> FinalizedRollout: + return FinalizedRollout( + rollout_id=rollout_id, + valid=False, + rejection_reason=reason, + token_ids=[], + token_mask=[], + logprobs=[], + prompt_len=0, + reward=reward, + staging_keys=staging_keys, + ) + + if receipt is None: + return rejected("missing_receipt", []) + try: + parsed = RolloutReceipt.model_validate(receipt) + except ValueError as error: + return rejected(f"invalid_receipt:{error}", []) + staging_keys = [record.staging_key for record in parsed.manifest] + if parsed.rollout_id != rollout_id: + return rejected(f"identity_mismatch:{parsed.rollout_id}", staging_keys) + if parsed.failure_reason is not None: + return rejected(f"rollout_failed:{parsed.failure_reason}", staging_keys) + if parsed.capture_poisoned: + return rejected("capture_poisoned", staging_keys) + if not parsed.manifest: + return rejected("empty_manifest", staging_keys) + + try: + snapshots = self._source.fetch(staging_keys) + except KeyError as error: + return rejected(f"missing_staging_row:{error}", staging_keys) + + for record, snapshot in zip(parsed.manifest, snapshots): + if not ( + len(snapshot.token_ids_delta) + == len(snapshot.token_mask_delta) + == len(snapshot.logprobs_delta) + ): + return rejected(f"misaligned_delta:{record.call_id}", staging_keys) + if any(m not in (0.0, 1.0) for m in snapshot.token_mask_delta): + return rejected(f"invalid_token_mask:{record.call_id}", staging_keys) + if any(not math.isfinite(p) for p in snapshot.logprobs_delta): + return rejected(f"non_finite_logprob:{record.call_id}", staging_keys) + if record.delta_len != len(snapshot.token_ids_delta) or ( + snapshot.prev_len + record.delta_len != record.cum_len + ): + return rejected(f"length_mismatch:{record.call_id}", staging_keys) + if snapshot.weight_version != record.weight_version: + return rejected( + f"weight_version_mismatch:{record.call_id}", staging_keys + ) + digest = compute_staging_digest( + rollout_id=rollout_id, + call_id=record.call_id, + prev_len=snapshot.prev_len, + token_ids_delta=snapshot.token_ids_delta, + token_mask_delta=snapshot.token_mask_delta, + logprobs_delta=snapshot.logprobs_delta, + ) + if digest != record.digest: + return rejected(f"digest_mismatch:{record.call_id}", staging_keys) + + # Parent pointers are lineage state, not storage state: rejoin from + # the manifest before rebuilding (the storage rows carry them too, + # but the receipt is authoritative). + rejoined = [ + snapshot.model_copy(update={"parent_call_id": record.parent_call_id}) + for snapshot, record in zip(snapshots, parsed.manifest) + ] + try: + row = linearize( + rollout_id, + rejoined, + parsed.manifest, + terminal_hint=parsed.terminal_call_id, + ) + except (RebuildError, NotImplementedError) as error: + return rejected(f"rebuild_failed:{error}", staging_keys) + + weight_versions = [record.weight_version for record in parsed.manifest] + min_wv, max_wv = min(weight_versions), max(weight_versions) + if self._mixed_weight_version_policy == "reject" and min_wv != max_wv: + return rejected(f"mixed_weight_versions:{min_wv}..{max_wv}", staging_keys) + + return FinalizedRollout( + rollout_id=rollout_id, + valid=True, + rejection_reason=None, + token_ids=row.token_ids, + token_mask=row.token_mask, + logprobs=row.logprobs, + prompt_len=row.prompt_len, + reward=reward, + staging_keys=staging_keys, + min_wv=min_wv, + max_wv=max_wv, + ) + + # ── per group ─────────────────────────────────────────────────────────── + + def finalize_group( + self, + group_id: str, + rollout_ids: list[str], + receipts: list[Optional[dict[str, Any]]], + rewards: list[float], + *, + fallback_weight_version: int, + ) -> FinalizedGroup: + """Publish exactly N canonical rows for one prompt group. + + Blocking (TQ round trips); run via ``asyncio.to_thread`` from the + dispatch task. ``fallback_weight_version`` stamps a group none of + whose rollouts produced a valid row (placeholder-only groups still + need a staleness tag). + """ + assert len(rollout_ids) == len(receipts) == len(rewards), ( + "rollout_ids, receipts, and rewards must be parallel" + ) + rows = [ + self.finalize_rollout(rollout_id, receipt, reward=reward) + for rollout_id, receipt, reward in zip(rollout_ids, receipts, rewards) + ] + valid_rows = [row for row in rows if row.valid] + staging_keys = [key for row in rows for key in row.staging_keys] + metrics = { + "finalize/invalid_row_rate": 1.0 - len(valid_rows) / len(rows), + "finalize/calls_per_rollout": ( + sum(len(row.staging_keys) for row in rows) / len(rows) + ), + } + for row in rows: + if not row.valid: + print( + f" finalize: rollout {row.rollout_id} rejected " + f"({row.rejection_reason}) — placeholder", + flush=True, + ) + + group_min_wv = min( + (r.min_wv for r in valid_rows), default=fallback_weight_version + ) + group_max_wv = max( + (r.max_wv for r in valid_rows), default=fallback_weight_version + ) + + valid_fraction = len(valid_rows) / len(rows) + if ( + self._min_valid_fraction is not None + and valid_fraction < self._min_valid_fraction + ): + self._clear_staging(staging_keys) + metrics["finalize/group_dropped"] = 1.0 + return FinalizedGroup( + meta=None, + group_min_wv=group_min_wv, + group_max_wv=group_max_wv, + staging_keys=[], + metrics=metrics, + dropped=True, + ) + + # Placeholders borrow a valid sibling's prompt ids so per-prompt + # baselines group correctly; an all-placeholder group uses a single + # pad token (its rows all carry sample_mask 0 and never train). + sibling_prompt = ( + valid_rows[0].token_ids[: valid_rows[0].prompt_len] if valid_rows else [] + ) or [self._pad_token_id] + + n = len(rows) + seq_lens = [max(1, len(row.token_ids)) for row in rows] + max_len = max(seq_lens) + input_ids = torch.full((n, max_len), self._pad_token_id, dtype=torch.int64) + token_mask = torch.zeros((n, max_len), dtype=torch.float32) + logprobs = torch.zeros((n, max_len), dtype=torch.float32) + prompt_ids_for_adv = torch.tensor([sibling_prompt] * n, dtype=torch.int64) + sample_mask = torch.zeros(n, dtype=torch.float32) + lengths = torch.tensor(seq_lens, dtype=torch.long) + rewards_t = torch.tensor([row.reward for row in rows], dtype=torch.float32) + for i, row in enumerate(rows): + if not row.valid: + continue + length = len(row.token_ids) + input_ids[i, :length] = torch.tensor(row.token_ids, dtype=torch.int64) + token_mask[i, :length] = torch.tensor(row.token_mask, dtype=torch.float32) + logprobs[i, :length] = torch.tensor(row.logprobs, dtype=torch.float32) + sample_mask[i] = 1.0 + + train_batch = { + "input_ids": input_ids, + "input_lengths": lengths, + "generation_logprobs": logprobs, + "token_mask": token_mask, + "sample_mask": sample_mask, + "prompt_ids_for_adv": prompt_ids_for_adv, + "total_reward": rewards_t, + } + sample_ids, fields, tags = pack_payload( + train_batch, weight_version=group_min_wv, group_id=group_id + ) + assert sample_ids == rollout_ids, ( + "canonical sample ids must equal the gate-registered rollout ids: " + f"{sample_ids} != {rollout_ids}" + ) + self._call_dp( + "put_samples", + sample_ids=sample_ids, + partition_id=self._partition_id, + fields=fields, + tags=tags, + ) + self._clear_staging(staging_keys) + + meta = KVBatchMeta( + partition_id=self._partition_id, + task_name="train", + sample_ids=list(sample_ids), + fields=list(fields.keys()), + sequence_lengths=[int(s) for s in lengths.tolist()], + tags=[dict(t) for t in tags], + ) + return FinalizedGroup( + meta=meta, + group_min_wv=group_min_wv, + group_max_wv=group_max_wv, + # Already cleared; nothing left for eviction to clear. + staging_keys=[], + metrics=metrics, + ) + + # ── internals ─────────────────────────────────────────────────────────── + + def _clear_staging(self, staging_keys: list[str]) -> None: + if not staging_keys: + return + try: + self._staging.clear(staging_keys) + except Exception as error: # noqa: BLE001 — cleanup must not fail the group; TTL sweeps leftovers + print( + f" finalize: staging clear failed ({error}); TTL will sweep", + flush=True, + ) + + def _call_dp(self, method_name: str, **kwargs: Any) -> Any: + import ray + + method = getattr(self._dp_client, method_name) + remote = getattr(method, "remote", None) + if remote is not None: + return ray.get(remote(**kwargs)) + return method(**kwargs) diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 398b028f623..4db6efc61fe 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -15,6 +15,7 @@ import asyncio import copy import json +import uuid from typing import Any, Optional import torch @@ -65,15 +66,21 @@ def __init__( self._max_rollout_turns = max_rollout_turns self._policy_generation = policy_generation - async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: + async def run_rollout( + self, input_sample: DatumSpec, *, rollout_ids: Optional[list[str]] = None + ) -> PromptGroupRecord: """Run num_generations_per_prompt rollouts for one prompt. Args: input_sample: A single prompt (one DatumSpec entry). + rollout_ids: Unsupported here — token capture is NeMo-Gym only. Returns: PromptGroupRecord with num_generations_per_prompt completions. """ + assert rollout_ids is None, ( + "token capture (rollout_ids) is only supported on the NeMo-Gym path" + ) timer = Timer() timer_prefix = "timing/rollout" timer.start(f"{timer_prefix}/total") @@ -404,11 +411,17 @@ def __init__( self._validate_init_params() - async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: + async def run_rollout( + self, input_sample: DatumSpec, *, rollout_ids: Optional[list[str]] = None + ) -> PromptGroupRecord: """Run num_generations_per_prompt rollouts for one prompt. Args: input_sample: A single prompt (one DatumSpec entry). + rollout_ids: Token-capture mode: gate-registered rollout ids, one + per generation, injected into each row's + ``responses_create_params.metadata`` (the zero-agent-change + side-channel carrier). Returns: PromptGroupRecord with num_generations_per_prompt completions. @@ -417,7 +430,7 @@ async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: timer_prefix = "timing/rollout" timer.start(f"{timer_prefix}/total") - rollout_inputs = self._build_inputs(input_sample) + rollout_inputs = self._build_inputs(input_sample, rollout_ids=rollout_ids) completions, prompt_message_log, rollout_metrics = await self._run_rollouts( rollout_inputs, timer, timer_prefix ) @@ -448,7 +461,9 @@ def _validate_init_params(self) -> None: "Please set `max_rollout_turns` to 1." ) - def _build_inputs(self, input_sample: DatumSpec) -> list[dict]: + def _build_inputs( + self, input_sample: DatumSpec, *, rollout_ids: Optional[list[str]] = None + ) -> list[dict]: """Build N row dicts from input_sample, applying generation config params.""" # Build a template row from the input_sample's extra_env_info, applying generation params. template_row: dict = copy.deepcopy(input_sample["extra_env_info"]) # type: ignore @@ -469,10 +484,17 @@ def _build_inputs(self, input_sample: DatumSpec) -> list[dict]: ) # Build N rows with distinct rowidxs so run_rollouts can sort them correctly. + if rollout_ids is not None: + assert len(rollout_ids) == self._num_generations_per_prompt, ( + "token-capture rollout ids must be one per generation" + ) rows = [] for i in range(self._num_generations_per_prompt): row = copy.deepcopy(template_row) row["_rowidx"] = i + if rollout_ids is not None: + metadata = row["responses_create_params"].setdefault("metadata", {}) + metadata["ng_rollout_id"] = rollout_ids[i] rows.append(row) return rows @@ -505,6 +527,21 @@ async def _run_rollouts( def _result_to_completion(self, result: dict) -> Completion: """Convert one run_rollouts result dict into a Completion.""" + if "receipt" in result: + # Receipt mode (token capture): the result is token-free — the + # message_log is empty and the canonical row is rebuilt by the + # finalizer from staged deltas. The receipt and rollout id ride + # env_extras for the finalize step. + env_extras = dict(result["full_result"]) + env_extras["ng_receipt"] = result["receipt"] + env_extras["ng_rollout_id"] = result["rollout_id"] + return Completion( + message_log=result["message_log"], + env_extras=env_extras, + truncated=False, + reward=float(result["full_result"]["reward"]), + ) + # Tensorize token fields. _tensorize_by_key(result["message_log"], "token_ids") _tensorize_by_key( @@ -532,17 +569,39 @@ def _compute_rollout_metrics( """Aggregate per-sample and per-agent metrics.""" # Prepare lists of values for each metric. total_reward = [c.reward for c in completions] - turn_count = [ - sum(1 for m in c.message_log if m["role"] == "user") for c in completions - ] - # token metrics - total_tokens = [ - sum(len(m["token_ids"]) for m in c.message_log) for c in completions - ] - assistant_tokens = [ - sum(len(m["token_ids"]) for m in c.message_log if m["role"] == "assistant") - for c in completions - ] + receipt_mode = bool(completions) and "ng_receipt" in completions[0].env_extras + if receipt_mode: + # Token-free receipts: token accounting comes from the manifest + # (cum_len of the deepest chain; delta sums as the generation + # proxy) instead of a message_log walk. + manifests = [ + ((c.env_extras.get("ng_receipt") or {}).get("manifest") or []) + for c in completions + ] + turn_count = [len(m) for m in manifests] + total_tokens = [ + max((entry["cum_len"] for entry in m), default=0) for m in manifests + ] + assistant_tokens = [ + sum(entry["delta_len"] for entry in m) for m in manifests + ] + else: + turn_count = [ + sum(1 for m in c.message_log if m["role"] == "user") + for c in completions + ] + # token metrics + total_tokens = [ + sum(len(m["token_ids"]) for m in c.message_log) for c in completions + ] + assistant_tokens = [ + sum( + len(m["token_ids"]) + for m in c.message_log + if m["role"] == "assistant" + ) + for c in completions + ] # truncated metrics truncated = [c.truncated for c in completions] @@ -560,8 +619,12 @@ def _compute_rollout_metrics( "truncation_rate": sum(truncated) / n, } - # Agent-level metrics. - agent_extras = [c.env_extras for c in completions] + # Agent-level metrics. Receipts are lineage records, not agent + # results — keep them (and their manifests) out of the logged table. + agent_extras = [ + {k: v for k, v in c.env_extras.items() if k not in ("ng_receipt",)} + for c in completions + ] for key in agent_extras[0].keys(): values = [ float(r[key]) # type: ignore @@ -598,10 +661,15 @@ def __init__( generation_config: Optional[GenerationConfig] = None, use_nemo_gym: bool = False, tq_buffer: Optional[TQReplayBuffer] = None, + finalizer: Optional[Any] = None, ) -> None: assert num_generations_per_prompt >= 1, ( "num_generations_per_prompt must be >= 1" ) + if finalizer is not None: + assert use_nemo_gym, ( + "token capture (finalizer) is only supported on the NeMo-Gym path" + ) if not use_nemo_gym: rollout_cls = AsyncRolloutImpl @@ -628,6 +696,8 @@ def __init__( self._tokenizer = tokenizer self._num_generations_per_prompt = num_generations_per_prompt self._tq_buffer = tq_buffer + self._finalizer = finalizer + self._env_handles = env_handles self._weight_version: int = 0 def set_weight_version(self, version: int) -> None: @@ -638,8 +708,13 @@ def set_weight_version(self, version: int) -> None: """ self._weight_version = int(version) - async def run_rollout(self, input_sample: DatumSpec) -> PromptGroupRecord: - return await self._impl.run_rollout(input_sample) + async def run_rollout( + self, input_sample: DatumSpec, *, rollout_ids: Optional[list[str]] = None + ) -> PromptGroupRecord: + if rollout_ids is None: + # Legacy path: keep the impl call signature byte-identical. + return await self._impl.run_rollout(input_sample) + return await self._impl.run_rollout(input_sample, rollout_ids=rollout_ids) async def generate_and_push( self, input_sample: DatumSpec, *, target_step: Optional[int] = None @@ -653,6 +728,9 @@ async def generate_and_push( assert self._tq_buffer is not None, ( "generate_and_push requires tq_buffer to be set at __init__" ) + if self._finalizer is not None: + await self._generate_and_finalize(input_sample, target_step=target_step) + return start_version = self._weight_version group_id = self._tq_buffer.reserve( weight_version=start_version, target_step=target_step @@ -675,3 +753,66 @@ async def generate_and_push( # releases the capacity permit on the same exception). self._tq_buffer.abort(group_id) raise + + async def _generate_and_finalize( + self, input_sample: DatumSpec, *, target_step: Optional[int] = None + ) -> None: + """Token-capture dispatch: receipts in, canonical rows via the finalizer. + + Mints the group's rollout ids up front — sample ids and gate-registered + rollout ids are the same strings (``{group_id}_g{i}``) — reserves the + slot with them so cleanup can name what it owns before a receipt + exists, and commits via ``commit_finalized`` with the group's + min/max call weight versions. + """ + start_version = self._weight_version + group_id = str(uuid.uuid4()) + rollout_ids = [ + f"{group_id}_g{i}" for i in range(self._num_generations_per_prompt) + ] + self._tq_buffer.reserve( + weight_version=start_version, + target_step=target_step, + group_id=group_id, + rollout_ids=rollout_ids, + ) + try: + record = await self.run_rollout(input_sample, rollout_ids=rollout_ids) + receipts = [c.env_extras.get("ng_receipt") for c in record.completions] + rewards = [float(c.reward) for c in record.completions] + finalized = await asyncio.to_thread( + self._finalizer.finalize_group, + group_id, + rollout_ids, + receipts, + rewards, + fallback_weight_version=start_version, + ) + record.rollout_metrics.update(finalized.metrics) + if finalized.dropped: + # min_valid_fraction_per_group rejected the group: nothing + # was published, so drop the slot like a failed dispatch. + self._tq_buffer.abort(group_id) + raise RuntimeError( + f"token capture: group {group_id} dropped " + "(min_valid_fraction_per_group)" + ) + await self._tq_buffer.commit_finalized( + group_id, + finalized.meta, + finalized.group_min_wv, + finalized.group_max_wv, + staging_keys=finalized.staging_keys, + ) + except BaseException: + self._tq_buffer.abort(group_id) + # Best-effort gate cleanup: no receipt will ever seal these ids. + nemo_gym_env = self._env_handles.get("nemo_gym") + if nemo_gym_env is not None: + try: + await nemo_gym_env.fail_rollouts.remote( + rollout_ids, reason="dispatch_failed" + ) + except Exception as error: # noqa: BLE001 — TTL is the backstop + print(f"fail_rollouts({group_id}) failed: {error}", flush=True) + raise diff --git a/nemo_rl/models/generation/vllm/vllm_worker_async.py b/nemo_rl/models/generation/vllm/vllm_worker_async.py index 2574015dbb1..a70b7201475 100644 --- a/nemo_rl/models/generation/vllm/vllm_worker_async.py +++ b/nemo_rl/models/generation/vllm/vllm_worker_async.py @@ -202,6 +202,9 @@ def __init__( # the set_rollout_weight_version fan-out from the SC's _sync_weights. self.token_capture = None self._rollout_weight_version = 0 + # In-flight captured calls keyed by id(request): (ActiveCall, the + # exact engine prompt ids recorded at preprocess time). + self._capture_calls: dict[int, tuple[Any, list[int]]] = {} super().__init__( config, @@ -473,8 +476,62 @@ async def set_rollout_weight_version(self, version: int) -> None: """Rotate the weight version stamped on subsequent captured calls.""" self._rollout_weight_version = int(version) + def _begin_request_capture(self, request: Any, prompt_token_ids: list[int]) -> None: + """Admit one gate-forwarded call into the capture layer. + + Called from preprocess_chat once the exact engine prompt is known + (post-splice in token-in mode, full render in text mode). No-op + unless capture is installed and the request carries the gate's + ``ng_capture`` context. + """ + capture = self.token_capture + context = getattr(request, "ng_capture", None) + if capture is None or not context: + return + call = capture.begin_call( + rollout_id=context["rollout_id"], + call_id=context["call_id"], + parent_call_id=context.get("parent_call_id"), + prev_len=int(context.get("prev_len") or 0), + mode=context.get("mode") or "text", + stream=bool(getattr(request, "stream", False)), + ) + self._capture_calls[id(request)] = (call, list(prompt_token_ids)) + + def _finish_request_capture(self, request: Any, content: dict) -> dict: + """Stage the finished call and ride its coords on the response. + + Fail-closed (§ 3.5): the sink write happens inside complete_call — + the coords exist only after the bytes are durable, and any capture + failure degrades to capture_failed coords without breaking the + completion. Token ids and logprobs are stripped: the staged delta is + the only token store on this path, so the worker->gate hop carries + text + delta ids + coords only (§ 3.2). + """ + state = self._capture_calls.pop(id(request), None) + if state is None: + return content + call, prompt_token_ids = state + payload = dict(content) + # vLLM's OpenAI response carries no prompt ids; the adapter reads the + # preprocess-time engine prompt off the payload (see + # nemo_gym.token_id_capture.adapters.vllm.extract_prompt_ids). + payload["prompt_token_ids"] = prompt_token_ids + coords = self.token_capture.complete_call_from_response(call, payload) + for choice in content.get("choices") or []: + choice.pop("logprobs", None) + content["ng_commit_coords"] = coords.model_dump() + return content + + def _abort_request_capture(self, request: Any, *, reason: str) -> None: + """Drop the in-flight capture state for a request that errored.""" + state = self._capture_calls.pop(id(request), None) + if state is not None and self.token_capture is not None: + self.token_capture.fail_call(state[0], reason=reason) + # ruff: noqa def _setup_vllm_openai_api_server(self, app: FastAPI) -> FastAPI: + worker_self = self from copy import deepcopy from logging import Filter as LoggingFilter from logging import LogRecord @@ -645,6 +702,11 @@ async def preprocess_chat( actual_request_max_tokens, res[1][0]["prompt_token_ids"], ) + # Token capture, text mode: the full render is the exact + # engine prompt. + worker_self._begin_request_capture( + request, res[1][0]["prompt_token_ids"] + ) return res last_assistant_message_idx = None @@ -702,6 +764,10 @@ async def preprocess_chat( final_prompt_token_ids, ) + # Token capture, token-in mode: the spliced prompt is the + # exact engine prompt. + worker_self._begin_request_capture(request, final_prompt_token_ids) + return res ######################################## @@ -713,6 +779,9 @@ class NeMoRLChatCompletionRequest( NeMoRLOpenAIChatRequestMixin, ChatCompletionRequest ): required_prefix_token_ids: Optional[List[int]] = None + # Gate-authoritative token capture: the call identity the gate + # attaches (rollout_id, call_id, parent_call_id, prev_len, mode). + ng_capture: Optional[dict[str, Any]] = None # vLLM 0.20 routes both /v1/chat/completions and /tokenize through # OpenAIServingRender.preprocess_chat, so the prefix-token override @@ -782,6 +851,7 @@ async def create_chat_completion( # max_model_len during tokenization, instead of returning an # ErrorResponse. Convert to HTTP 400 so the Gym proxy can # detect context-length overflow and handle it gracefully. + worker_self._abort_request_capture(request, reason="context_length") return JSONResponse( content={ "error": { @@ -792,15 +862,24 @@ async def create_chat_completion( }, status_code=400, ) + except BaseException: + worker_self._abort_request_capture(request, reason="engine_error") + raise if isinstance(generator, ErrorResponse): + worker_self._abort_request_capture(request, reason="error_response") return JSONResponse( content=generator.model_dump(), status_code=generator.error.code ) elif isinstance(generator, ChatCompletionResponse): - return JSONResponse(content=generator.model_dump()) + content = generator.model_dump() + # Token capture: stage the delta and ride the coords on the + # response; strips logprobs/ids (no-op when capture is off). + content = worker_self._finish_request_capture(request, content) + return JSONResponse(content=content) + worker_self._abort_request_capture(request, reason="streaming_response") return StreamingResponse(content=generator, media_type="text/event-stream") ######################################## diff --git a/pyrefly.toml b/pyrefly.toml index 28683742c87..668b9c939b4 100644 --- a/pyrefly.toml +++ b/pyrefly.toml @@ -132,6 +132,7 @@ project-includes = [ "nemo_rl/evals/__init__.py", "nemo_rl/evals/answer_parsing.py", "nemo_rl/experience/__init__.py", + "nemo_rl/experience/blackbox_finalizer.py", "nemo_rl/experience/interfaces.py", "nemo_rl/experience/rollout_manager.py", "nemo_rl/experience/rollouts.py", diff --git a/tests/unit/algorithms/test_advantage_validity.py b/tests/unit/algorithms/test_advantage_validity.py new file mode 100644 index 00000000000..64c1bc829b9 --- /dev/null +++ b/tests/unit/algorithms/test_advantage_validity.py @@ -0,0 +1,54 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""S4: validity-aware GRPO baseline (token-capture placeholder rows).""" + +import torch + +from nemo_rl.algorithms.advantage_estimator import GRPOAdvantageEstimator + + +def _estimator(**overrides) -> GRPOAdvantageEstimator: + config = {"use_leave_one_out_baseline": False, "normalize_rewards": False} + config.update(overrides) + return GRPOAdvantageEstimator(config, loss_config=None) + + +def test_invalid_rows_do_not_bias_the_baseline(): + prompt_ids = torch.zeros( + 4, 3, dtype=torch.long + ) # one shared prompt (2D, as prompt_ids_for_adv) + # The last row is a token-capture placeholder: reward 0, sample_mask 0. + rewards = torch.tensor([1.0, 3.0, 2.0, 0.0]) + valid_mask = torch.tensor([1.0, 1.0, 1.0, 0.0]) + mask = torch.ones(4, 5) + + adv = _estimator().compute_advantage( + prompt_ids, rewards, mask, valid_mask=valid_mask + ) + # Baseline over valid rows only: mean(1,3,2) = 2 (placeholder's 0 excluded). + assert torch.allclose(adv[0], torch.full((5,), -1.0)) + assert torch.allclose(adv[1], torch.full((5,), 1.0)) + assert torch.allclose(adv[2], torch.full((5,), 0.0)) + + +def test_none_valid_mask_keeps_legacy_all_valid_behavior(): + prompt_ids = torch.zeros(2, 3, dtype=torch.long) + rewards = torch.tensor([1.0, 3.0]) + mask = torch.ones(2, 3) + legacy = _estimator().compute_advantage(prompt_ids, rewards, mask) + explicit = _estimator().compute_advantage( + prompt_ids, rewards, mask, valid_mask=torch.ones(2) + ) + assert torch.equal(legacy, explicit) diff --git a/tests/unit/data_plane/test_blackbox_finalizer.py b/tests/unit/data_plane/test_blackbox_finalizer.py new file mode 100644 index 00000000000..58ecdae854c --- /dev/null +++ b/tests/unit/data_plane/test_blackbox_finalizer.py @@ -0,0 +1,247 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""S4: BlackboxFinalizer against a live TQ simple backend. + +Drives the S1 golden call sequences end to end: stage the fixture's delta +rows via TQTokenSink, hand the fixture receipt to the finalizer, and require +the published canonical rows to match the fixture's frozen training row. +Every rejection path (missing rows, digest corruption, poisoned receipts) +must yield a masked placeholder — always N rows — and the group publisher's +min/max weight versions and staging cleanup must hold. + +Marked nemo_gym (run with ``--nemo-gym-only``): the finalizer delegates +rebuild semantics to Gym's staging package. +""" + +from __future__ import annotations + +import pytest +import torch + +nemo_gym = pytest.importorskip("nemo_gym.token_id_capture.staging") + +from nemo_gym.token_id_capture.staging.conformance.kit import ( # noqa: E402 + build_fixture_artifacts, + f32, + load_fixture, +) + +from nemo_rl.data_plane.tq_token_sink import ( # noqa: E402 + STAGING_FIELDS, + TQTokenSink, +) +from nemo_rl.experience.blackbox_finalizer import BlackboxFinalizer # noqa: E402 + +pytestmark = pytest.mark.nemo_gym + +STAGING_PARTITION = "rollout_staging_fin_test" +CANONICAL_PARTITION = "rollout_data_fin_test" +PAD = 0 + + +@pytest.fixture() +def partitions(tq_client): + tq_client.register_partition( + partition_id=STAGING_PARTITION, + fields=list(STAGING_FIELDS), + num_samples=64, + consumer_tasks=["finalize"], + ) + tq_client.register_partition( + partition_id=CANONICAL_PARTITION, + fields=[ + "input_ids", + "input_lengths", + "generation_logprobs", + "token_mask", + "sample_mask", + "prompt_ids_for_adv", + "total_reward", + ], + num_samples=64, + consumer_tasks=["train"], + ) + yield + tq_client.clear_samples(sample_ids=None, partition_id=STAGING_PARTITION) + tq_client.clear_samples(sample_ids=None, partition_id=CANONICAL_PARTITION) + + +def _finalizer(tq_client, **overrides) -> BlackboxFinalizer: + kwargs = dict( + partition_id=CANONICAL_PARTITION, + staging_partition=STAGING_PARTITION, + pad_token_id=PAD, + mixed_weight_version_policy="allow", + min_valid_fraction_per_group=None, + ) + kwargs.update(overrides) + return BlackboxFinalizer(tq_client, **kwargs) + + +def _stage_fixture(tq_client, name: str, *, rollout_id: str | None = None): + """Stage one golden fixture's rows (optionally re-keyed to rollout_id) + and return (receipt_dict, expected LinearizedRow).""" + fixture = load_fixture(name) + if rollout_id is not None: + fixture = dict(fixture) + fixture["rollout_id"] = rollout_id + records, _, receipt, row = build_fixture_artifacts(fixture) + sink = TQTokenSink(tq_client, staging_partition=STAGING_PARTITION) + for record in records: + assert sink.stage(record).ok + return receipt.model_dump(), row + + +def test_finalize_rollout_reproduces_the_golden_row(tq_client, partitions): + receipt, expected = _stage_fixture(tq_client, "worked_example") + finalizer = _finalizer(tq_client) + row = finalizer.finalize_rollout("g7_r0", receipt, reward=1.0) + assert row.valid, row.rejection_reason + assert row.token_ids == expected.token_ids + assert row.token_mask == [f32(m) for m in expected.token_mask] + assert row.logprobs == [f32(p) for p in expected.logprobs] + assert row.prompt_len == expected.prompt_len + # The worked example spans a single weight version (wv 4 throughout). + assert (row.min_wv, row.max_wv) == (4, 4) + + +def test_finalize_rollout_rejections(tq_client, partitions): + finalizer = _finalizer(tq_client) + assert ( + finalizer.finalize_rollout("r", None, reward=0.0).rejection_reason + == "missing_receipt" + ) + + receipt, _ = _stage_fixture(tq_client, "single_call", rollout_id="rej_a") + poisoned = dict(receipt, capture_poisoned=True) + assert ( + finalizer.finalize_rollout("rej_a", poisoned, reward=0.0).rejection_reason + == "capture_poisoned" + ) + empty = dict(receipt, manifest=[], terminal_call_id=None) + assert ( + finalizer.finalize_rollout("rej_a", empty, reward=0.0).rejection_reason + == "empty_manifest" + ) + wrong_identity = finalizer.finalize_rollout("someone_else", receipt, reward=0.0) + assert (wrong_identity.rejection_reason or "").startswith("identity_mismatch") + + # A manifest naming rows that were never staged. + ghost = dict(receipt) + ghost["manifest"] = [ + {**entry, "staging_key": "ghost/row"} for entry in receipt["manifest"] + ] + missing = finalizer.finalize_rollout("rej_a", ghost, reward=0.0) + assert (missing.rejection_reason or "").startswith("missing_staging_row") + + # Digest corruption: break the manifest digest so recomputation misses. + corrupted = dict(receipt) + corrupted["manifest"] = [ + {**entry, "digest": "0" * 64} for entry in receipt["manifest"] + ] + bad = finalizer.finalize_rollout("rej_a", corrupted, reward=0.0) + assert (bad.rejection_reason or "").startswith("digest_mismatch") + + +def test_mixed_weight_version_policy_reject(tq_client, partitions): + receipt, _ = _stage_fixture(tq_client, "mixed_weight_versions", rollout_id="mix_r0") + receipt["rollout_id"] = "mix_r0" + allow_row = _finalizer(tq_client).finalize_rollout("mix_r0", receipt, reward=0.0) + assert allow_row.valid + assert allow_row.min_wv < allow_row.max_wv + reject_row = _finalizer( + tq_client, mixed_weight_version_policy="reject" + ).finalize_rollout("mix_r0", receipt, reward=0.0) + assert (reject_row.rejection_reason or "").startswith("mixed_weight_versions") + + +def _fetch_rows(tq_client, sample_ids): + return tq_client.get_samples( + sample_ids=sample_ids, + partition_id=CANONICAL_PARTITION, + select_fields=[ + "input_ids", + "input_lengths", + "generation_logprobs", + "token_mask", + "sample_mask", + "prompt_ids_for_adv", + "total_reward", + ], + ) + + +def test_finalize_group_publishes_n_rows_with_placeholder(tq_client, partitions): + group_id = "grp1" + receipt, expected = _stage_fixture( + tq_client, "worked_example", rollout_id=f"{group_id}_g0" + ) + receipt["rollout_id"] = f"{group_id}_g0" + rollout_ids = [f"{group_id}_g0", f"{group_id}_g1"] + + finalizer = _finalizer(tq_client) + finalized = finalizer.finalize_group( + group_id, + rollout_ids, + [receipt, None], # second rollout lost its receipt -> placeholder + [1.0, 0.0], + fallback_weight_version=9, + ) + assert not finalized.dropped + assert finalized.meta is not None + assert finalized.meta.sample_ids == rollout_ids + # Group staleness comes from the valid rollout's calls (wv 4), not the fallback. + assert (finalized.group_min_wv, finalized.group_max_wv) == (4, 4) + assert finalized.metrics["finalize/invalid_row_rate"] == 0.5 + + rows = _fetch_rows(tq_client, rollout_ids) + sample_mask = torch.as_tensor(rows["sample_mask"]).flatten() + assert sample_mask.tolist() == [1.0, 0.0] + valid_len = len(expected.token_ids) + input_ids = torch.as_tensor(rows["input_ids"][0]).flatten() + assert input_ids[:valid_len].tolist() == expected.token_ids + # Placeholder borrows the valid sibling's prompt for baseline grouping. + prompt = expected.token_ids[: expected.prompt_len] + adv_prompt_valid = torch.as_tensor(rows["prompt_ids_for_adv"][0]).flatten() + adv_prompt_placeholder = torch.as_tensor(rows["prompt_ids_for_adv"][1]).flatten() + assert adv_prompt_valid.tolist() == prompt + assert adv_prompt_placeholder.tolist() == prompt + placeholder_mask = torch.as_tensor(rows["token_mask"][1]).flatten() + assert placeholder_mask.sum().item() == 0.0 + rewards = torch.as_tensor(rows["total_reward"]).flatten() + assert rewards.tolist() == [1.0, 0.0] + + # The finalizer cleared its staged rows after publishing. + with pytest.raises(KeyError): + finalizer._source.fetch([receipt["manifest"][0]["staging_key"]]) + + +def test_finalize_group_min_valid_fraction_drops(tq_client, partitions): + group_id = "grp2" + rollout_ids = [f"{group_id}_g0", f"{group_id}_g1"] + finalizer = _finalizer(tq_client, min_valid_fraction_per_group=0.5) + finalized = finalizer.finalize_group( + group_id, + rollout_ids, + [None, None], + [0.0, 0.0], + fallback_weight_version=3, + ) + assert finalized.dropped + assert finalized.meta is None + assert (finalized.group_min_wv, finalized.group_max_wv) == (3, 3) + with pytest.raises((KeyError, RuntimeError, ValueError)): + rows = _fetch_rows(tq_client, rollout_ids) + assert not rows # nothing published diff --git a/tests/unit/experience/test_rollout_manager.py b/tests/unit/experience/test_rollout_manager.py index 3a4517241c7..47b2b957451 100644 --- a/tests/unit/experience/test_rollout_manager.py +++ b/tests/unit/experience/test_rollout_manager.py @@ -132,6 +132,8 @@ def _make_manager(buffer: _FakeBuffer, impl: _FakeImpl) -> RolloutManager: mgr._tokenizer = None mgr._num_generations_per_prompt = 1 mgr._tq_buffer = buffer + mgr._finalizer = None + mgr._env_handles = {} mgr._weight_version = 0 return mgr @@ -238,6 +240,8 @@ async def _second_run(_sample): second_mgr._tokenizer = None second_mgr._num_generations_per_prompt = 1 second_mgr._tq_buffer = buf + second_mgr._finalizer = None + second_mgr._env_handles = {} second_mgr._weight_version = 0 async def _drive(): @@ -284,7 +288,9 @@ def test_failed_commit_aborts_reserved_slot(self): """Commit failures (e.g. evicted slot) also abort the reservation.""" class _CommitBoomBuffer(_FakeBuffer): - async def commit(self, group_id, record, start_weight_version, end_weight_version): + async def commit( + self, group_id, record, start_weight_version, end_weight_version + ): raise ValueError("no live slot") buf = _CommitBoomBuffer() @@ -840,3 +846,168 @@ def _last_assistant_token_ids(msg_log): assert orig_val == pytest.approx(new_val), ( f"rollout_metrics[{key!r}] mismatch — original {orig_val}, manager {new_val}" ) + + +class _FakeFinalizedGroup: + def __init__(self, *, dropped=False): + self.meta = None if dropped else "meta-sentinel" + self.group_min_wv = 3 + self.group_max_wv = 4 + self.staging_keys = [] + self.metrics = {"finalize/invalid_row_rate": 0.0} + self.dropped = dropped + + +class _FakeFinalizer: + def __init__(self, *, dropped=False): + self.calls: list[tuple] = [] + self._dropped = dropped + + def finalize_group( + self, group_id, rollout_ids, receipts, rewards, *, fallback_weight_version + ): + self.calls.append( + (group_id, rollout_ids, receipts, rewards, fallback_weight_version) + ) + return _FakeFinalizedGroup(dropped=self._dropped) + + +class _FakeCaptureBuffer(_FakeBuffer): + def __init__(self): + super().__init__() + self.reserve_rollout_ids: list[list[str] | None] = [] + self.commit_finalized_calls: list[tuple] = [] + + def reserve( + self, *, weight_version, target_step=None, group_id=None, rollout_ids=None + ): + self.reserve_rollout_ids.append(rollout_ids) + return super().reserve( + weight_version=weight_version, + target_step=target_step, + group_id=group_id, + rollout_ids=rollout_ids, + ) + + async def commit_finalized( + self, group_id, meta, group_min_wv, group_max_wv, *, staging_keys=None + ): + self.commit_finalized_calls.append( + (group_id, meta, group_min_wv, group_max_wv, staging_keys) + ) + return meta + + +class _FakeGymEnvHandle: + """NemoGym actor stand-in exposing fail_rollouts.remote.""" + + def __init__(self): + self.failed: list[tuple[list[str], str]] = [] + outer = self + + class _FailRollouts: + def remote(self, rollout_ids, reason): + outer.failed.append((list(rollout_ids), reason)) + + async def _done(): + return None + + return _done() + + self.fail_rollouts = _FailRollouts() + + +def _receipt_record(rollout_ids, receipts): + completions = [ + Completion( + message_log=[], + env_extras={"reward": 0.5, "ng_receipt": receipt, "ng_rollout_id": rid}, + truncated=False, + reward=0.5, + ) + for rid, receipt in zip(rollout_ids, receipts) + ] + return PromptGroupRecord( + prompt_idx=0, + prompt=[], + extra_env_info={}, + metadata={"task_name": "nemo_gym"}, + completions=completions, + rollout_metrics={}, + ) + + +def _make_capture_manager(buf, finalizer, *, on_run=None, num_generations=2): + mgr = object.__new__(RolloutManager) + mgr._tokenizer = None + mgr._num_generations_per_prompt = num_generations + mgr._tq_buffer = buf + mgr._finalizer = finalizer + mgr._env_handles = {"nemo_gym": _FakeGymEnvHandle()} + mgr._weight_version = 7 + + class _CaptureImpl: + def __init__(self): + self.seen_rollout_ids = None + + async def run_rollout(self, _sample, *, rollout_ids=None): + self.seen_rollout_ids = rollout_ids + if on_run is not None: + await on_run(_sample) + return _receipt_record( + rollout_ids, [{"rollout_id": rid} for rid in rollout_ids] + ) + + mgr._impl = _CaptureImpl() + return mgr + + +class TestGenerateAndFinalizeFlow: + def test_mints_ids_finalizes_and_commits(self): + buf = _FakeCaptureBuffer() + finalizer = _FakeFinalizer() + mgr = _make_capture_manager(buf, finalizer) + + _run(mgr.generate_and_push({"prompt": "p"}, target_step=5)) + + # Rollout ids were minted from the reserved group id and threaded + # end to end: reserve -> impl -> finalizer. + (group_id,) = buf._slots + expected_ids = [f"{group_id}_g0", f"{group_id}_g1"] + assert buf.reserve_rollout_ids == [expected_ids] + assert mgr._impl.seen_rollout_ids == expected_ids + (fin_group_id, fin_ids, receipts, rewards, fallback_wv) = finalizer.calls[0] + assert fin_group_id == group_id + assert fin_ids == expected_ids + assert [r["rollout_id"] for r in receipts] == expected_ids + assert rewards == [0.5, 0.5] + assert fallback_wv == 7 + # commit_finalized carried the group's min/max call versions. + assert buf.commit_finalized_calls == [(group_id, "meta-sentinel", 3, 4, [])] + # The legacy commit path was not used and nothing failed at the gate. + assert buf.commit_calls == [] + assert mgr._env_handles["nemo_gym"].failed == [] + + def test_dropped_group_aborts_slot(self): + buf = _FakeCaptureBuffer() + mgr = _make_capture_manager(buf, _FakeFinalizer(dropped=True)) + with pytest.raises(RuntimeError, match="min_valid_fraction"): + _run(mgr.generate_and_push({"prompt": "p"})) + assert buf.commit_finalized_calls == [] + assert len(buf.abort_calls) >= 1 + + def test_failed_dispatch_aborts_and_fails_gate_rollouts(self): + buf = _FakeCaptureBuffer() + + async def _boom(_sample): + raise RuntimeError("rollout exploded") + + mgr = _make_capture_manager(buf, _FakeFinalizer(), on_run=_boom) + with pytest.raises(RuntimeError, match="rollout exploded"): + _run(mgr.generate_and_push({"prompt": "p"})) + assert buf.commit_finalized_calls == [] + assert len(buf.abort_calls) == 1 + (failed_ids, reason) = mgr._env_handles["nemo_gym"].failed[0] + (group_id,) = [buf.abort_calls[0]] + assert failed_ids == [f"{group_id}_g0", f"{group_id}_g1"] + assert reason == "dispatch_failed" diff --git a/tests/unit/models/generation/test_vllm_token_capture_hosting.py b/tests/unit/models/generation/test_vllm_token_capture_hosting.py index 28edb951409..65111211205 100644 --- a/tests/unit/models/generation/test_vllm_token_capture_hosting.py +++ b/tests/unit/models/generation/test_vllm_token_capture_hosting.py @@ -171,3 +171,142 @@ def test_generation_set_rollout_weight_version_fans_out(): version=7, run_rank_0_only_axes=["tensor_parallel", "pipeline_parallel"], ) + + +# --------------------------------------------------------------------------- +# S4: the request-path hookup (begin -> finish/abort around a served call) +# --------------------------------------------------------------------------- + + +class _FakeRequest(SimpleNamespace): + pass + + +def _worker_with_capture(sink: _MemorySink): + from nemo_gym.token_id_capture.adapters.vllm import VLLMCaptureAdapter + + worker = _fake_worker() + worker._capture_calls = {} + worker.token_capture = RolloutTokenCapture( + sink=sink, + weight_version_fn=lambda: worker._rollout_weight_version, + adapter=VLLMCaptureAdapter(), + ) + return worker + + +def _served_content(gen_ids, logprobs): + return { + "choices": [ + { + "index": 0, + "message": {"role": "assistant", "content": "x"}, + "logprobs": { + "content": [ + {"token": f"token_id:{t}", "logprob": lp} + for t, lp in zip(gen_ids, logprobs) + ] + }, + } + ] + } + + +def test_request_capture_round_trip_stages_and_rides_coords(): + sink = _MemorySink() + worker = _worker_with_capture(sink) + request = _FakeRequest( + ng_capture={ + "rollout_id": "r0", + "call_id": "c1", + "parent_call_id": None, + "prev_len": 0, + "mode": "text", + }, + stream=False, + ) + VllmAsyncGenerationWorkerImpl._begin_request_capture(worker, request, [10, 11, 12]) + content = _served_content([13, 14], [-0.1, -0.2]) + content = VllmAsyncGenerationWorkerImpl._finish_request_capture( + worker, request, content + ) + # Bytes were staged before the coords existed (fail-closed ordering). + assert len(sink.records) == 1 + assert sink.records[0].token_ids_delta == [10, 11, 12, 13, 14] + coords = content["ng_commit_coords"] + assert coords["disposition"] == "staged" + assert (coords["delta_len"], coords["cum_len"]) == (5, 5) + # Logprobs never transit worker -> gate; state map is drained. + assert ( + "logprobs" not in content["choices"][0] + or content["choices"][0]["logprobs"] is None + ) + assert worker._capture_calls == {} + + +def test_request_capture_token_in_prev_len_chains(): + sink = _MemorySink() + worker = _worker_with_capture(sink) + request = _FakeRequest( + ng_capture={ + "rollout_id": "r0", + "call_id": "c2", + "parent_call_id": "c1", + "prev_len": 3, + "mode": "token_in", + }, + stream=False, + ) + spliced_prompt = [10, 11, 12, 20, 21] # exact prefix + fresh suffix + VllmAsyncGenerationWorkerImpl._begin_request_capture( + worker, request, spliced_prompt + ) + content = VllmAsyncGenerationWorkerImpl._finish_request_capture( + worker, request, _served_content([22], [-0.5]) + ) + coords = content["ng_commit_coords"] + assert coords["parent_call_id"] == "c1" + assert (coords["delta_len"], coords["cum_len"]) == (3, 6) + assert sink.records[0].token_ids_delta == [20, 21, 22] + + +def test_request_capture_is_a_noop_without_context_or_capture(): + sink = _MemorySink() + worker = _worker_with_capture(sink) + plain = _FakeRequest(stream=False) # no ng_capture attribute + VllmAsyncGenerationWorkerImpl._begin_request_capture(worker, plain, [1, 2]) + content = { + "choices": [{"message": {"role": "assistant"}, "logprobs": {"content": []}}] + } + out = VllmAsyncGenerationWorkerImpl._finish_request_capture( + worker, plain, dict(content) + ) + assert "ng_commit_coords" not in out + assert out["choices"][0]["logprobs"] is not None # untouched off the capture path + assert sink.records == [] + + +def test_request_capture_abort_fails_the_call_and_drains_state(): + sink = _MemorySink() + worker = _worker_with_capture(sink) + request = _FakeRequest( + ng_capture={ + "rollout_id": "r0", + "call_id": "c1", + "parent_call_id": None, + "prev_len": 0, + "mode": "text", + }, + stream=False, + ) + VllmAsyncGenerationWorkerImpl._begin_request_capture(worker, request, [1, 2]) + VllmAsyncGenerationWorkerImpl._abort_request_capture( + worker, request, reason="engine_error" + ) + assert worker._capture_calls == {} + assert sink.records == [] + # A late finish after abort is a no-op (state already drained). + out = VllmAsyncGenerationWorkerImpl._finish_request_capture( + worker, request, _served_content([3], [-0.1]) + ) + assert "ng_commit_coords" not in out From 8408cba1570a406031624ad5a10e56d8824fab69 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 16:54:41 -0700 Subject: [PATCH 36/44] =?UTF-8?q?feat(sc):=20S5=20verification=20=E2=80=94?= =?UTF-8?q?=20gate=20metrics,=20row=20dump,=20byte=20counters,=20capture?= =?UTF-8?q?=20L1=20test,=20SWE=20A/B=20runbook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gate/* metrics into the SC logger per train step (token_in_rate derived; fetch failures logged, never fatal) via RolloutManager.gate_metrics() - env-gated train-row dump (NRL_SC_DUMP_TRAIN_ROWS) at both canonical publish sites for the legacy-vs-capture row diff - env-gated HTTP byte counters: RL vLLM-worker mirror (NRL_HTTP_BYTES_DIR) of the Gym middleware; Gym submodule pin 05986b04 -> e3b3eac6 (NG_HTTP_BYTES_DIR middleware) - fix: re-raise aiohttp.ClientResponseError as picklable RuntimeError in run_rollouts (CIMultiDictProxy headers cannot cross the Ray boundary; active flag-off, disclosed for the S5 gate) - capture-enabled SC gym functional test in L1 (full mode) - swe/: token-capture vs legacy perf A/B runbook + launch tooling - design docs (v2 + gate-authoritative + implementation log) into the docs tree S5 evidence recorded in docs/design-docs/tq-gym-gate-authoritative-implementation-log.md. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- 3rdparty/Gym-workspace/Gym | 2 +- .../tq-gym-async-single-controller.md | 467 ++++++++++++ ...m-gate-authoritative-implementation-log.md | 167 ++++- docs/design-docs/tq-gym-gate-authoritative.md | 697 ++++++++++++++++++ docs/index.md | 3 + .../algorithms/async_utils/replay_buffer.py | 8 + nemo_rl/algorithms/single_controller.py | 25 + nemo_rl/environments/nemo_gym.py | 13 +- nemo_rl/experience/blackbox_finalizer.py | 8 + nemo_rl/experience/rollout_manager.py | 13 + nemo_rl/experience/row_dump.py | 77 ++ .../generation/vllm/vllm_worker_async.py | 8 + nemo_rl/utils/http_byte_counter.py | 82 +++ pyrefly.toml | 2 + swe/SWE_RUN.md | 183 +++++ swe/aggregate_perf.py | 113 +++ swe/launch_swe_ab.sh | 70 ++ swe/make_capture_config.py | 50 ++ .../L1_Functional_Tests_SingleController.sh | 3 + 19 files changed, 1988 insertions(+), 3 deletions(-) create mode 100644 docs/design-docs/tq-gym-async-single-controller.md create mode 100644 docs/design-docs/tq-gym-gate-authoritative.md create mode 100644 nemo_rl/experience/row_dump.py create mode 100644 nemo_rl/utils/http_byte_counter.py create mode 100644 swe/SWE_RUN.md create mode 100644 swe/aggregate_perf.py create mode 100755 swe/launch_swe_ab.sh create mode 100644 swe/make_capture_config.py diff --git a/3rdparty/Gym-workspace/Gym b/3rdparty/Gym-workspace/Gym index 05986b04e6b..e3b3eac6c0c 160000 --- a/3rdparty/Gym-workspace/Gym +++ b/3rdparty/Gym-workspace/Gym @@ -1 +1 @@ -Subproject commit 05986b04e6ba6db9d6fe0c61ad9da979e615e3a5 +Subproject commit e3b3eac6c0cdfba9ce7b95e20cec13b04b17ca58 diff --git a/docs/design-docs/tq-gym-async-single-controller.md b/docs/design-docs/tq-gym-async-single-controller.md new file mode 100644 index 00000000000..2e9e525be73 --- /dev/null +++ b/docs/design-docs/tq-gym-async-single-controller.md @@ -0,0 +1,467 @@ +# Token Capture v2 in the Async SingleController Pipeline + +Design and implementation plan for running NeMo-Gym rollouts through the +**Token Capture v2** architecture — Gym-owned capture, NeMo-RL as the byte +mover — inside the async SingleController (SC) GRPO pipeline on this branch. + +**Target architecture:** the v2 ownership split (`tq_gym_v2.md` / +`tq_gym_v2_rollout.html` in the prototype checkout). **Reference +implementation / donor code:** the sync-only prototype at +`/lustre/fsw/portfolios/coreai/users/pthombre/gym/RL/` +(branch `pranav/tq_gym_prototype`), which proved the dataflow and the perf +numbers but predates the v2 ownership split — it is quarry, not foundation. + +**Sources reconciled:** + +- This branch (`yukih/sc-entrypoint`): async SC pipeline — + `nemo_rl/algorithms/single_controller.py`, `single_controller_utils/`, + `experience/rollout_manager.py`, `async_utils/replay_buffer.py` + (`TQReplayBuffer`), `async_utils/staleness_sampler.py`, `models/policy/tq_policy.py`. +- v2 design docs: `tq_gym_v2.md` + `tq_gym_v2_rollout.html` (ownership split, + `parent_hint`, stage acks, enriched seal receipts, terminal-hint linearize). +- Prototype (donor): `experience/rollout_writer.py`, + `experience/blackbox_finalizer.py`, `experience/staged_token_source.py`, + `models/generation/vllm/vllm_worker_async.py`, `algorithms/grpo_sync.py`; + Gym pinned as an editable workspace member with the ingress-gate stack. +- Gym upstream: PR [#1967](https://github.com/NVIDIA-NeMo/Gym/pull/1967) + (closed) and the live [#2124](https://github.com/NVIDIA-NeMo/Gym/pull/2124)–#2128 + stack (open; a reduced file-backed capture core — not yet the v2 surface). + +--- + +## 1. Goal + +Replace the async SC's Gym rollout path — where every generated token transits +Gym HTTP responses, a Ray return, and an SC-side tensorize before reaching the +TransferQueue — with the v2 capture pipeline: + +- **Gym owns every decision** about tokens and lineage: envelope parsing, hint + confirmation, parent fallback, delta/mask construction, hash chain, digest, + stage→commit ordering, the registry state machine, rebuild, and + linearization. +- **NeMo-RL implements exactly two protocols and hosts two processes**: a + `TokenSink` that lands bytes in TQ, a `ForestCursor` that transports + registry calls to a Ray actor shell hosting Gym's state machine, plus the + finalizer orchestration (fetch, reconcile policy, publish) and the + `weight_version` value. +- The SC pipeline consumes the result through its existing seams: a buffer + slot per prompt group, canonical rows in the existing `rollout_data` + partition, unchanged train pump. + +Proven upside from the prototype (sync loop, same dataflow): **−46.9 % HTTP +bytes/generated token, −55.7 % HTTP exchanges, −45.3 % terminal Gym→RL +bytes/sample, −4.3 % total step time (p50)**. v2 additionally converts the +`ambiguous_forest` rejection class (sub-agent branches) into trainable rows +via terminal-hint linearization. + +## 2. The v2 contract + +Everything above the line ships in Gym's `nemo_gym/token_capture/` leaf +package (no fastapi, no Ray, no TQ imports); everything below is the entire +surface NeMo-RL writes. + +``` +GYM records.py StagedCallRecord, StageAck, DelegationEnvelope, ParentHint, + ForestCandidate, Reservation, ParentClaim, CommitCoords +GYM hashing.py hash_token_ids, compute_staging_digest, EMPTY_PREFIX_HASH, SCHEMA_VERSION +GYM protocols.py TokenSink.stage(rec) -> StageAck # data plane + ForestCursor.get_candidates/reserve/commit/fail # control plane +GYM forest.py ForestCursorStateMachine (+ CursorConflictError, + DuplicateRequestError, CursorFailedError) — retry-idempotent + reserve, parent validation, growth check, leases, manifest order +GYM capture.py RolloutTokenCapture.begin_call / complete_call — hint confirm, + candidate-scan fallback, delta build, fail-closed ordering +GYM rebuild.py staged deltas -> TokenEntrys -> linearize(policy, terminal_hint) +GYM adapters/vllm.py hook wiring + token extraction; install_capture(...) +GYM gate admission, call_id mint, trajectory tree + coordinate ledger, + parent_hint stamping, stage-ack backfill, seal -> enriched receipt +──────────────────────────────────────────────────────────────────────────── +RL TQTokenSink(dp_client, partition="rollout_staging") # one method: stage() +RL RayForestCursor(registry_actor) # ~20-line transport +RL RolloutForestRegistry (Ray actor SHELL hosting Gym's state machine) +RL finalizer orchestration: row fetch, reconcile policy, publish, placeholders +RL worker setup (once): install_capture(worker, sink=…, cursor=…, + weight_version_fn=lambda: self._rollout_weight_version) +RL weight_version value (trainer state) +``` + +Wire behavior (v2 additions over the prototype): the gate stamps a +`DelegationEnvelope` with a `parent_hint` (~120 B); the worker confirms the +hint with **one hash** and only falls back to the candidate scan on a miss; +the `StageAck` (~100 B) rides the response back so the gate's coordinate +ledger stays current; seal returns an **enriched receipt** with +`terminal_call_id` + a token-free tree summary, letting the finalizer run +`linearize(policy="main_chain_only", terminal_hint=…)`. + +### 2.1 Gap between v2 and what exists today + +| v2 element | Today | +|---|---| +| `nemo_gym/token_capture/` package | Does not exist. The prototype's Gym pin has the ingress gate + a flat manifest (no tree/ledger, no hints, no acks); upstream #2124 is a file-backed capture core without the gate/forest surface. | +| `ForestCursorStateMachine` in Gym | Implemented **in NeMo-RL** (`rollout_writer.py`), same semantics — the direct donor for Gym's `forest.py`. | +| `TQTokenSink` / `RayForestCursor` / `install_capture` | Staging is inlined in `vllm_worker_async.py`; workers call the registry actor directly; wiring is `configure_rollout_writer(...)` pushed from the driver. | +| `parent_hint` / stage acks / enriched receipts | Absent — worker always candidate-scans; `stage_disposition` is inferred at seal; branching rollouts reject as `ambiguous_forest`. | +| `rebuild.py` in Gym | Split across NeMo-RL (`staged_token_source.py`) and Gym (`trajectory/builder.py`). | + +The migration is therefore **two coordinated tracks** (§ 7): Gym lands +`token_capture` (largely by relocating prototype-proven code per the v2 doc's +own 6-step migration), and NeMo-RL builds the framework half against the v2 +protocol names from day one — so nothing is written twice. + +## 3. Current async SC rollout path (what changes) + +``` +_rollout_pump ─► RolloutManager.generate_and_push(prompt) + ├─ tq_buffer.reserve(weight_version) # slot, dispatch order + ├─ AsyncNemoGymRolloutImpl.run_rollout + │ └─ NemoGym.run_rollouts.remote(rows) # tokens echoed back ✗ + └─ tq_buffer.commit(group_id, record, …) + ├─ record_to_train_batch(record) # tensorize on SC ✗ + └─ dp_client.put_samples(N rows) # rollout_data partition +_train_pump ─► sampler.select → logprobs → _advantage_pump → train_microbatch_from_meta +_sync_weights ─► pause dispatches → WeightSynchronizer.sync_weights → resume +``` + +The two ✗ steps disappear: Gym's capture library, running inside the vLLM +worker, lands every token in TQ at generation time through NeMo-RL's +`TQTokenSink`. The SC keeps its reserve/commit slot discipline — `commit` +becomes *"finalize the group's staged rows and record the resulting meta."* + +## 4. Target design + +### 4.1 Data flow + +``` +SC _rollout_pump + └─ generate_and_push(prompt, target_step) + ├─ tq_buffer.reserve(weight_version=v_start) (unchanged) + ├─ mint N rollout_ids, register at gate (new) + ├─ NemoGym.run_rollouts.remote(rows + rollout_ids) (token-free) + │ agent ⇄ gate (tree + ledger, parent_hint) ⇄ vLLM worker + │ Gym capture: begin_call (hint confirm | scan | new root) + │ → cursor.reserve [RayForestCursor → registry shell] + │ complete_call: delta/hash/digest + │ → sink.stage(record) [TQTokenSink → rollout_staging] + │ → cursor.commit(coords) fail-closed + │ StageAck rides the response → gate ledger backfill + ├─ seal each rollout → enriched RolloutReceipt (+ reward) (new) + ├─ finalize group: receipt × manifest reconcile → fetch + Gym + │ re-verify → rebuild → linearize(terminal_hint) → (new) + │ N canonical rows → put_samples(rollout_data, {group_id}_g{i}) + └─ tq_buffer.commit_finalized(group_id, meta, versions) (changed) + +SC _train_pump: unchanged, except advantage/validity handling (§ 4.5) +SC _sync_weights: additionally rotates the workers' weight_version (§ 4.4) +``` + +Two TQ partitions, distinct lifecycles: + +- `rollout_staging` — one delta row per model call, keyed + `{rollout_id}/{call_id}`, written by `TQTokenSink.stage` (the framework's + entire hot-path contribution); cleared by the finalizer after publication, + by eviction, and by TTL. +- `rollout_data` (existing SC partition) — canonical per-sample training rows; + today's schema (`input_ids`, `input_lengths`, `generation_logprobs`, + `token_mask`, `sample_mask`, `prompt_ids_for_adv`, `total_reward`) + **plus `trajectory_valid_mask`**; lifecycle unchanged (select → train → + `clear_samples`). + +### 4.2 NeMo-RL components (the whole framework surface) + +- **`nemo_rl/data_plane/tq_token_sink.py`** — `TQTokenSink`: maps a + `StagedCallRecord` to a TensorDict row + tags and calls `put_samples`. TQ + vocabulary appears nowhere else in the capture path. +- **`nemo_rl/experience/rollout_writer.py`** (slimmed) — `RayForestCursor` + (each method awaits the corresponding registry-actor method) and + `RolloutForestRegistry`, reduced to an actor **shell**: + `self.state = ForestCursorStateMachine(...)` imported from Gym `forest.py`; + every method delegates 1:1. Lease/TTL knobs come from config; semantics, + idempotency, and the exception taxonomy are Gym's. +- **Worker setup** — one call at vLLM async-worker startup: + `install_capture(worker, sink=TQTokenSink(...), cursor=RayForestCursor(...), + weight_version_fn=lambda: self._rollout_weight_version)`. The + driver-pushed `set_rollout_weight_version(int)` remains the mechanism that + updates the value the closure reads. +- **Finalizer** (`nemo_rl/experience/blackbox_finalizer.py`, reworked) — + orchestration only: get manifest from the registry shell, reconcile against + the enriched receipt, fetch rows, call Gym's `rebuild` + verification + functions (the same bytes the worker hashed), call + `linearize(policy="main_chain_only", terminal_hint=receipt.terminal_call_id)`, + publish canonical rows or masked placeholders, clear staging + registry. +- **`TQReplayBuffer.commit_finalized`** and the setup wiring in + `single_controller_utils/setup.py` (§ 6). + +### 4.3 Where finalization runs; group assembly + +Finalization is CPU + TQ I/O work, run per prompt group inside the existing +`generate_and_push` dispatch task via `asyncio.to_thread` — a group's slot +flips ready only when its canonical rows exist, preserving today's ordering. +If finalize latency (~60 ms/rollout measured on sync) shows up in +`exposed_generation`, promote to a small finalizer actor pool behind the same +`finalize_group(group_id, rollout_ids, receipts) -> GroupFinalizeResult` seam. + +Group semantics (GRPO needs N generations per prompt group): + +1. Finalize each of the N rollouts; any rejection (manifest mismatch, digest + mismatch, non-finite logprobs, residual ambiguity) becomes a masked + placeholder row — `trajectory_valid_mask=0`, `sample_mask=0`, reward + zeroed — so the group always publishes exactly N rows and + `shard_meta_for_dp` invariants hold. With terminal-hint linearize, the + dominant v1 rejection class (`ambiguous_forest`) becomes a trained main + chain with verified-but-untrained side branches. +2. `prompt_ids_for_adv` for a placeholder is copied from a verified sibling; + a fully rejected group keeps a constant fallback and zero advantage. +3. Rewards come from the seal receipts, never from token traffic. +4. Optional `min_valid_fraction_per_group`: below it, drop the group entirely + (slot removed, staging cleared, capacity permit released — the SC's + over-sampling machinery already tolerates disappearing groups). + +### 4.4 Weight versions, refit, and staleness — the async-specific design + +Nothing in the v2 docs covers async; these are the new decisions: + +1. **Per-call tagging is the source of truth.** `weight_version_fn` reads + worker state that `_sync_weights` rotates: after + `weight_synchronizer.sync_weights()` and before `_rollout_permitted.set()`, + the SC fans out `set_rollout_weight_version(trainer_version)`. Every + `StagedCallRecord` then carries the true version of the weights that + produced it — strictly better than SC-side start/end stamps. + + > **TODO (T1, deferred): atomic version rotation.** The driver fan-out + > races with the weight swap per worker: calls completing inside the refit + > window can be mis-tagged by ±1 version. Tolerable for the MVP matrix + > (`staleness_window` + `allow`, which absorbs ±1 by design; no worse than + > the legacy async path, which cannot see straddles at all). The fix — + > thread `weight_version` through `WeightSynchronizer.sync_weights()` into + > the worker's update handler so swap and stamp happen in one task, with + > capture sampling the version at `begin_call` and `complete_call` + > (mismatch → stamp older + `wv_straddled` flag) — is a **prerequisite** + > for `strict_on_policy` / `mixed_weight_version_policy: reject`, which + > must not ship on the racy mechanism. +2. **Group staleness = oldest call version.** `finalize_group` computes + `group_min_wv`/`group_max_wv` across all calls of all N rollouts; + `commit_finalized` stores `group_min_wv` as the slot's effective version. + The `StalenessSampler` is unchanged — its window test now uses the + conservative oldest-call version, so a refit-straddling rollout is evicted + exactly when its oldest tokens age out. The reserve-time stamp remains for + dispatch-order/quota accounting only. +3. **Mixed-version groups are a policy, not an error.** New + `async_rl.mixed_weight_version_policy: allow | reject`: + - `allow` (default under `staleness_window`): finalize normally; log + `wv_spread = group_max_wv − group_min_wv`. + - `reject` (forced by `strict_on_policy`): version-spanning rollouts become + placeholders. `strict_on_policy` should also re-enable the drain + (`_inflight_rollouts → 0`) before syncing, making spans impossible; + `reject` is then a safety net. +4. **`generation_logprobs` are behavior-policy logprobs** for the version that + generated each token; the per-token importance-sampling correction in + `ClippedPGLossFn` handles mixed-version sequences, and the staleness window + bounds how far off-policy they can drift. + +### 4.5 Buffer, eviction, and cleanup + +Every path where a group can die must clear **three** stores — the SC slot, +the canonical rows, and the staging rows + registry state: + +- `TQReplayBuffer.remove(..., remove_in_dp=True)` (used by `sampler.evict`) + additionally clears `rollout_staging` keys and calls + `registry.clear_rollout(rid)` for the group's rollouts (slots record their + rollout_ids at reserve time). +- Post-train `clear_samples` is unchanged — staging was already cleared at + publication. +- SC shutdown / cancelled dispatch tasks must `fail_rollout` registered + rollout_ids and clear staged rows (`try/finally`, mirroring the existing + `sem.release()` discipline); otherwise staging leaks until `cursor_ttl_s`. +- Backpressure: `max_buffered_rollouts` bounds groups; staging is additionally + bounded by `max_inflight_prompts × num_generations_per_prompt × + max_rollout_turns` delta rows — size the partition accordingly and keep the + registry's `expire_stale` TTL as the backstop. + +### 4.6 Constraints + +- vLLM async backend first (Gym's `adapters/vllm.py`); an SGLang port is a new + adapter file plus the same `install_capture` call — the SC-side design is + engine-blind by construction. +- Streaming and `n>1` per request are rejected by the adapter (v1 behavior, + unchanged until Gym's adapter supports them). +- `rollout_max_attempts_to_avoid_lp_nan` must be 1 (gate registration is + create-only; sealing is terminal). Non-finite logprobs → placeholder, not + retry. +- Router replay requires `routed_experts` in the staged-record `extras` — + supported by the v2 record shape, deferred until needed. +- Gateway→worker identity rides the `DelegationEnvelope`; the vLLM endpoint + must remain network-isolated (no auth on that hop). + +## 5. Config surface + +```yaml +data_plane: + token_capture: # renamed from the prototype's rollout_writer + enabled: false + # no shadow mode: verification is offline row-equivalence (see § 7 M3) + staging_partition: rollout_staging + finalize_timeout_s: 30.0 + lease_ttl_s: 30.0 # registry shell → Gym state machine + cursor_ttl_s: 3600.0 # also gate registration TTL + linearize_policy: main_chain_only # forwarded to Gym rebuild + +async_rl: + mixed_weight_version_policy: allow | reject # § 4.4 + min_valid_fraction_per_group: 0.0 # § 4.3 (0 = always publish) +``` + +`strict_on_policy` auto-forces `mixed_weight_version_policy: reject` (same +pattern as its existing forcing of staleness/over-sampling). Misconfiguration +(`token_capture.enabled` without `env.should_use_nemo_gym`, or an unsupported +backend) raises at `setup_single_controller` time. + +## 6. Component changes (this repo) + +| Component | Change | +|---|---| +| `data_plane/tq_token_sink.py` (new) | `TQTokenSink` — `StagedCallRecord` → TensorDict row + tags → `put_samples`; the only file that knows TQ on the hot path | +| `experience/rollout_writer.py` (new, slim) | `RayForestCursor` transport; `RolloutForestRegistry` actor shell hosting Gym's `ForestCursorStateMachine` | +| `experience/blackbox_finalizer.py` (new) | Orchestration-only finalizer over Gym `rebuild`/`linearize`; per-group assembly, placeholders, `group_min_wv` | +| `single_controller_utils/setup.py` | Launch registry shell; register staging partition; pass gate config (registration/seal, TTLs, control token) into `spinup_nemo_gym_actor`; hand sink/cursor factories to generation setup | +| `models/generation/vllm/` | Worker startup calls Gym `install_capture(sink, cursor, weight_version_fn)`; keep `set_rollout_weight_version` fan-out; delete any inlined staging logic | +| `experience/rollout_manager.py` | Black-box mode: mint rollout_ids, register → dispatch (token-free) → seal → collect enriched receipts → `finalize_group` → `commit_finalized` | +| `async_utils/replay_buffer.py` | Slots record rollout_ids; `commit_finalized(group_id, meta, group_min_wv, group_max_wv)`; `remove()` clears staging + registry | +| `single_controller.py` | `_sync_weights` rotates worker weight_version; teardown fails/clears in-flight rollouts; metrics: `wv_spread`, hint hit rate, wasted hints, invalid-row rate, finalize latency | +| `environments/nemo_gym.py` | Register/seal control-plane helpers; gate config synthesis; receipts returned with token-free results | +| `data_plane/schema.py`, `interfaces.py`, `single_controller_utils/config.py` | Staging fields (from Gym `SCHEMA_VERSION`), `TokenCaptureConfig`, `AsyncRLConfig` additions; `AdvantageConfig` validity awareness | + +**Gym dependency:** a build containing `nemo_gym/token_capture/` and the v2 +gate (tree + ledger, hints, acks, enriched receipts). Until released, pin the +Gym branch where Track A lands (the prototype pin `6ea5810` is the starting +point; upstream #2124–#2128 should converge into it). + +## 7. Implementation plan + +**Bring-up first.** The MVP runs entirely out of this repo against the +vendored Gym pin: capture logic and the `ForestCursorStateMachine` are ported +from the prototype into NeMo-RL **behind the v2-named seams** (`TokenSink`, +`ForestCursor`, `install_capture`-shaped worker setup, defined locally). +Track A — relocating those internals into Gym's `token_capture` — is deferred +to hardening (T6) and, by construction, changes no SC-facing code when it +lands. The MVP config matrix is restricted to `staleness_window` + +`mixed_weight_version_policy: allow`; `strict_on_policy`, `reject`, and +`force_in_order` raise `NotImplementedError` at setup until T1/T4. + +### MVP (get it running) — one PR, five sign-off-gated stages + +The MVP is developed on a single branch and lands as **one PR**, built in five +stages. Each stage is its own signed-off commit (series), keeps the tree green +in isolation (S1–S3 are dormant behind `token_capture.enabled=false`), and +ends at a **review gate: the stage diff, test results, and any deviations +from this doc are presented for explicit user sign-off before the next stage +begins.** Protocol/record shapes freeze at the S1 gate. + +- **S1 — token_capture primitives.** `nemo_rl/experience/token_capture/` + (protocols, records + id grammar + `staging_key`, hashing, `forest.py` + state machine — all ported from the prototype behind v2 names), + `TQTokenSink`, `RayForestCursor` + registry shell, staging schema, + `TokenCaptureConfig`. Forest/sink unit tests against the protocol boundary. +- **S2 — vLLM worker capture.** `capture.py` (candidate-scan only), + `adapters/vllm.py` `install_capture`, generation fan-outs + (`configure_token_capture`, `set_rollout_weight_version`), + `prepare_token_capture` partition registration. Worker unit tests: + stage→commit ordering, fail-closed, version stamping. +- **S3 — gate control plane + finalizer.** Register/seal helpers, receipts + through `run_rollouts`, NaN-retry hard error; `blackbox_finalizer` + + `staged_token_source`; `finalize_group` (always N rows, placeholders with + sibling `prompt_ids_for_adv`, `group_min_wv`/`group_max_wv`, + `min_valid_fraction_per_group`). +- **S4 — SC integration, direct mode.** Config validation (MVP matrix only — + strict modes raise), setup wiring (§ 6), rollout-manager capture mode, + `commit_finalized` + cleanup in the buffer, `_sync_weights` version + fan-out, teardown sweep, validity-aware advantages (**baseline mean/std + over valid rows only; invalid rows get advantage 0** — unit-tested in this + stage), metrics (finalize p50/p99, invalid rate, `wv_spread`, registry RPC + latency). Gate evidence includes a 2-GPU manual run. +- **S5 — verification, no shadow mode.** Fixed-seed job on legacy and direct + paths, training rows dumped from TQ and diffed offline; reward-curve + comparison; capture-enabled functional test wired into + `L1_Functional_Tests_SingleController.sh`. S5 sign-off = MVP acceptance; + the PR opens after it (or earlier as a draft, decided at the S1 gate). + +### Hardening TODOs (ordered) + +- **T1 — atomic weight-version rotation** (§ 4.4 TODO). Prerequisite for T4. +- **T2 — failure sweep + chaos test.** Registry/gate actor death → fail + affected dispatch tasks, release permits, clear orphaned staging keys; + kill-registry-mid-step test. First, because bring-up debugging kills actors. +- **T3 — finalizer isolation.** Dedicated bounded executor + own DP client so + a TQ stall cannot starve the trainer's `to_thread` calls. +- **T4 — strict modes.** `strict_on_policy` (with drain re-enabled), + `mixed_weight_version_policy: reject`, and `force_in_order` (which matches + on the reserve-time `target_step` only; `group_min_wv` governs only the + window modes). +- **T5 — calls-per-rollout cap.** Gate-side admission limit with a + registry-side backstop — the design's only unbounded resource. +- **T6 — Track A: relocate into Gym** (below) + the rollout-id contract: one + id grammar/validator, gate as sole `call_id` minter (unifying with + upstream's `model_call_id`), `staging_key()` defined in Gym `records.py`, + `DelegationEnvelope` as the only gate→worker carrier. +- **T7 — scale.** Registry sharding by `hash(rollout_id)` (driven by the M2 + latency counter), cross-repo metrics channel (Gym counters riding the seal + receipt), finalizer actor pool, consistent-hash rollout→worker affinity. + +### Track A — Gym: land `token_capture` (deferred to T6; mostly relocation) +1. Move hashing + record dataclasses + `build_staging_delta` from the + prototype into `nemo_gym/token_capture/` (digests byte-identical — the + prototype's shadow/digest tests are the check); move + `ForestCursorStateMachine` + exception taxonomy into `forest.py` with its + unit tests (the NeMo-RL implementation in the prototype's + `rollout_writer.py` is the donor). +2. Define `TokenSink`/`ForestCursor` protocols; wire capture through them. +3. Move the capture algorithm (`_prepare_rollout_request` / + `_stage_rollout_response` bodies) into `RolloutTokenCapture`. +4. Move the engine adapter into `adapters/vllm.py`; expose `install_capture`. +5. Move rebuild (`StagedSnapshotTokenSource` core) into `rebuild.py` + + `linearize(policy, terminal_hint)`. +6. Behavior additions: gate tree + ledger, `parent_hint`, stage acks, enriched + receipts. Ship the adapter conformance suite (golden captures → + byte-identical records/digests). + Steps 1–5 change no behavior and are exactly the package to upstream + (reconciling with the #2124 stack). + +Steps 1–5 change no behavior; the MVP's locally-hosted state machine and +capture logic are the donors, so the relocation is a swap behind the seams +from M1 — no SC-facing code changes. Until step 6 lands, the gate produces +v1 receipts (no hints/acks): capture always takes the candidate-scan fallback +and `linearize` runs without a terminal hint — the seams tolerate the v1 gate, +so nothing downstream waits on step 6; its features (hint hit rate, lower +`ambiguous_forest` rate) simply light up in existing metrics when it ships. + +**Post-MVP validation milestone (with T1–T4 landed):** 1-off async nightly +(`grpo-llama3.1-8b …-async-1off-single-controller`) in direct mode, plus a +perf report reproducing the sync measurements (HTTP bytes/token, step time) +on the async path. Unit tests accompanying T1/T4: sampler evicts by +oldest-call version; refit-straddling rollout finalizes under `allow`, +placeholders under `reject`; fully-rejected group releases capacity. + +## 8. Risks and open questions + +- **Gym release coupling.** `token_capture` becomes hot-path code in every + engine worker on Gym's release cadence; lease/TTL knobs and manifest shape + become Gym API. Mitigations from the v2 doc: `SCHEMA_VERSION` pinning, the + core package stays dependency-free, `adapters/vllm.py` lazily imports vLLM. + Until upstreamed, we carry the Gym branch pin. +- **Upstream convergence.** The open #2124–#2128 stack is a different + (file-backed) shape; Track A must reconcile with it or supersede it — + coordination with the Gym team is the schedule risk — which is why the MVP + runs entirely out of this repo and Track A is deferred to T6, insulated by + the protocol boundary. +- **Finalize latency on the rollout critical path.** ~60 ms/rollout hides + behind generation seconds, but async moves it out from behind training — + measured from M2 via the finalize-latency counter. +- **Placeholder-heavy groups** shift the GRPO baseline; the M2 advantage rule + (baseline over valid rows only) plus `min_valid_fraction_per_group` are the + mitigations. Needs a post-MVP experiment. +- **Checkpointing.** SC checkpointing is itself TODO; staging rows and + registry state are deliberately not checkpointed — in-flight rollouts are + abandoned on restore (registry TTL + create-only registration make this + safe), matching the buffer's restore semantics. +- **Multi-row rollouts.** GRPO grouping and reward attribution for + `all_leaves` linearization is explicitly undesigned in v2; out of scope — + `main_chain_only` trains the main chain and verifies side branches only. diff --git a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md index 803392722f3..a127bc759df 100644 --- a/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md +++ b/docs/design-docs/tq-gym-gate-authoritative-implementation-log.md @@ -369,4 +369,169 @@ All NeMo-RL-side; no Gym fork changes in this stage. ## S5 — verification -Status: not started (blocked on S4 sign-off) +Status: **in progress (2026-07-28).** S4 signed off ("Commit S4 start S5") +and committed as RL `6b32665ca`. Work items (§ 10 S5): fixed-seed +legacy-vs-capture row diff, reward-curve comparison, per-call HTTP bytes +vs the echo path (+ `token_in_rate` into the SC logger, deferred from S4), +chaos smoke (kill gate mid-step), capture-enabled functional test in +`L1_Functional_Tests_SingleController.sh` (blocked on the gitlink/CI +decision). S5 sign-off = MVP acceptance. + +### Row diff: legacy vs capture (2026-07-28) + +Method: env-gated row dump (`nemo_rl/experience/row_dump.py`, +`NRL_SC_DUMP_TRAIN_ROWS=`, no-op unless set) hooked at both canonical +publish sites; identical direct-invocation runs (same node/placement/data) +differing only in `token_capture.enabled`; offline matcher keyed by +`(weight_version, prompt_ids_for_adv)`. + +Constraints discovered (documented, not fixable in-scope): + +- **No per-request sampling determinism exists** (engine seed is + placement-derived; `SamplingParams` carries no seed; the Gym path + rejects `top_k` overrides at `rollout_manager.py:452`; dataset-level + `temperature` is overwritten by the generation config at + `rollout_manager.py:474`). +- `policy.generation.temperature=0` (greedy) reaches the engine but NaNs + the loss at iteration 1 on **both** paths identically (vLLM's degenerate + greedy logprobs → NaN grad norm) — so the byte diff is a one-step + (wv=0) comparison, and full-length curves run at temperature 1. +- vLLM is cross-run nondeterministic under continuous batching (logit + jitter with batch composition), bounding what any cross-run diff can + show. + +Results: + +- Temp-1 pair (10 steps, 80 rows/run): all 40 group keys matched 1:1, + **prompt prefixes byte-identical in every row**; generated suffixes + diverge (sampling, as expected). +- Greedy wv=0 pair (identical weights): **7/8 rows byte-identical in ids + and masks end-to-end** across two entirely different pipelines + (echo-splice-tensorize vs gate-TQ-finalizer). The 1/8 divergence is a + mid-generation argmax flip at a near-tie (candidate logprobs −1.01 vs + −0.97) — engine jitter, not pipeline drift. Logprob deltas on + identical-token rows: exactly 0.0 on several rows, ≤ 0.147 max + elsewhere (batch-composition numerics; a transformation bug would be + systematic, not zero-on-some-rows). +- Step-1 rows are all single-call at this sequence budget; cross-run + multi-turn splice fidelity is not separately re-proven here — it rests + on the S1 live token-in smoke, S3 gate e2e prefix chaining, the per-row + digest verification live in every capture run, and the capture run's + gen_kl_error (0.0375) matching legacy (0.038). + +### Reward-curve comparison (2026-07-28, temp-1 pair, 10 steps) + +- `train/reward` per step: **identical 10/10** — + `[0, 0, 0.25, 0, 0.25, 0.25, 0.25, 0.5, 0, 0]` on both paths (seeded + dataset order; same prompts per step; same reward outcomes). +- `train/gen_kl_error`: same band — legacy median 0.0379 (max 0.068), + capture median 0.0358 (max 0.046). +- `train/global_valid_seqs` = 8.0 every step on both paths. + +### Wire metrics (2026-07-28) + +- `gate/*` metrics wired into the SC logger (the S4 deferral): per-step + fetch of the gate's cumulative § 8 counters through a new + `RolloutManager.gate_metrics()` passthrough, logged with derived + `gate/token_in_rate`; fetch failures are swallowed loudly (metrics never + kill a step). Live reading recorded with the chaos run below. +- Per-call token-carrier bytes, computed from the temp-1 run's actual rows + (JSON as on the wire): legacy echo attachment + (`prompt_token_ids`+`generation_token_ids`+`generation_log_probs`) mean + **2,540 B/call** (8.6 B/token at ~296 tok/call) vs capture marker + **35 B/call** — **−98.6 %** on the gate→agent carrier for this + single-turn workload; multi-turn re-echo compounds the legacy side per + turn. The full HTTP-level perf report (bytes/token, step time, gate + latency) remains post-MVP validation per § 10. + +### Instrumented perf A/B (2026-07-28, user-requested; pulled forward from +### post-MVP validation) + +Method: env-gated ASGI byte counters on every HTTP server (Gym +`HttpByteCounterMiddleware` in `server_utils.py`, `NG_HTTP_BYTES_DIR`; RL +mirror `nemo_rl/utils/http_byte_counter.py` on the vLLM worker app, +`NRL_HTTP_BYTES_DIR`); identical 10-step runs at 1024 seq budget differing +only in the flag; per-hop aggregation + timing from TB metrics. + +| Metric | Legacy | Capture | Δ | +|---|---|---|---| +| HTTP bytes / trained token | 107.3 B | 69.1 B | **−35.6 %** | +| Total HTTP bytes (10 steps) | 2.52 MB | 1.64 MB | −35 % | +| `total_step_time` median | 4.48 s | 4.07 s | **−9.0 %** | +| `exposed_generation` median | 1.99 s | 1.65 s | **−16.8 %** | +| `valid_tokens/s/GPU` median | 30.8 | 34.7 | **+12.5 %** | + +Per-hop highlights: the worker's `/tokenize` route disappears entirely +(77 calls → 0); worker `/v1/chat/completions` response bytes 0.34 → 0.19 MB +(logprob echo gone); gate `/v1/responses` responses 0.28 → 0.13 MB (token +arrays → markers); even the verifier hop shrinks (0.37 → 0.23 MB in) since +agent histories no longer carry token arrays. Health parity: same KL band +(0.0376 vs 0.0413 median), identical `max_reward` 0.5, all rows valid. + +Caveats: this workload remains single-call per rollout even at 1024 +(gate counters: 80 registered/sealed, 0 token_in, 0 fallbacks — all roots), +so the echo's per-turn compounding and `token_in_rate` are not exercised — +the prototype's −46.9 % bytes/token multi-turn number remains the +reference; 10-step timing on a 0.6B model is directional, not a benchmark. + +Reading of the numbers (assessment): + +- **The bytes reduction is structural, not statistical** — it comes from + routes/payloads that categorically no longer exist (`/tokenize` gone, + logprob echo gone, token arrays → 35 B markers), and this single-call + workload is capture's *worst case*: legacy never paid its per-turn + history re-echo (roughly quadratic in turns) while capture stays + O(generated tokens). −35.6 % is a floor that grows with agentic depth + and context length. +- **The timing wins are plausibly real but not yet bankable**: one run + pair, n=10 medians, 0.6B model — variance on this stack can be + ±5–10 %. In their favor: a concrete mechanism (one fewer HTTP + round-trip per call + ~40 % smaller payloads on the generation critical + path) and the gain concentrating in `exposed_generation` (−16.8 %) + exactly where the mechanism predicts. Expect the relative timing win to + compress on large models (GPU decode dominates) while the bytes win + grows. +- **Capture is at minimum perf-neutral while buying provenance**: the + gate, staging writes, digest verification, and finalizer all sit in the + measured path and the capture run is faster, with identical training + health — the design's custody guarantees carry no perf tax. +- To make the timing claim quotable: 3–5 repeated pairs (variance bars) + and a genuinely multi-turn workload (untrimmed tools, larger budget), + which is also the run that measures a real `token_in_rate` — earmarked + as the post-MVP perf report (§ 10). + +### Chaos smoke: gate killed mid-step (2026-07-28) + +Method: capture run, `SIGKILL` to the verified `policy_model` (gate) +process after step 3, 3-minute observation, then teardown. (Four earlier +attempts were invalidated by harness bugs — orphaned wrapper teardown, +GPU-squatting orphan EngineCore, a pgrep pattern that couldn't match the +gate, a task timeout — all documented in the session log; none were +capture-path defects.) + +Verdict vs the § 7 failure model: + +- **No corruption, no crash**: the SC actor and run stayed alive; step + count froze at 3 — nothing trained on bad data after the kill, and the + three completed steps were healthy. +- **FINDING (S5 → H1): gate death is a silent stall, not the promised + loud failure.** The NemoGym actor's control-plane `register_rollouts` + call to the dead gate sat in Gym's `server_utils.request` retry loop — + observed at **retry=375+ over the full window** (`ClientOSError`, + unbounded for connection errors) — so the dispatch never failed, the § 7 + fail-path (abort slot → `fail_rollouts` → placeholders) never engaged, + and the run would stall indefinitely. § 7's "SC dispatch timeout" row + presumes a timeout that is not wired for control-plane calls. + Recommended fix (H1 scope, where the design already places the failure + sweep + kill-gate CI test): bound control-plane retries/time + (`RolloutControlClient` request timeout), so gate death surfaces as + failed dispatches + placeholders + staging TTL, per the § 7 table. +- Staging-TTL sweep not observable in a 3-minute window (TTL 3600 s); + covered by unit tests. + +S5 finding fixed en route: agent `/run` 500s raise +`aiohttp.ClientResponseError` out of `run_rollouts`, and Ray cannot pickle +its `CIMultiDictProxy` headers — the SC saw a masking `TypeError` instead +of the real error. Fixed in `environments/nemo_gym.py` (catch + re-raise +picklable `RuntimeError`). **Active with the flag off** (any legacy agent +500 hit the same masking); disclosed for the S5 gate. diff --git a/docs/design-docs/tq-gym-gate-authoritative.md b/docs/design-docs/tq-gym-gate-authoritative.md new file mode 100644 index 00000000000..27e8d7064fe --- /dev/null +++ b/docs/design-docs/tq-gym-gate-authoritative.md @@ -0,0 +1,697 @@ +# Token Capture v3: Gate Token Custody (Token-In / Token-Out) + +Design and implementation plan for running NeMo-Gym rollouts through a +**token-in/token-out** capture pipeline in the async SingleController (SC) +GRPO pipeline. The Gym gate (the model server every agent calls) becomes the +**custodian of token lineage**: it holds each rollout's cumulative token +buffer, serves exact token prefixes to vLLM workers, and returns token-free +receipts. Workers stage per-call token deltas + logprobs directly to the +TransferQueue (TQ); tokens make exactly one heavy hop, at generation time. + +This supersedes two earlier drafts: + +- the **v2 doc** (`tq-gym-async-single-controller.md`): two trackers (gate + message tree + RL-side registry actor), two Ray RPCs per model call; +- the **hash-lineage draft** of this doc: single gate tracker, but lineage + verified after the fact by worker-side hash confirmation. Review found its + claim-confirm was not computable for non-root parents and its candidate + set excluded forks; more importantly, a code survey (§ 2) showed the + hash machinery solves a problem the codebase does not have. + +The v2 doc remains the reference for inherited material where cited +(weight-version design § 6, parts of the failure model). + +--- + +## 1. Goal and design principle + +Replace the async SC's Gym rollout path — where every generated token +transits Gym HTTP responses (twice per turn, growing with history), a Ray +return, and an SC-side tensorize — with a pipeline where: + +- **Tokens rest at exactly two places**: the gate's per-rollout buffer + (in-flight custody) and TQ (durable staging + canonical rows). +- **Tokens move on exactly one heavy hop**: worker → TQ, once per model + call, carrying delta ids + logprobs + extras. +- **Every other hop is token-light**: gate→worker carries prefix ids + (replacing the text prompt, comparable size); worker→gate carries delta + ids only (~4 B/token, no logprobs); agent-facing messages and the Ray + return are token-free. +- **The integration is framework- and backend-portable.** Gym defines the + protocols and owns lineage (§ 3.0); an RL framework integrates by + implementing four small contracts (sink, source, weight-version provider, + wiring); an inference engine integrates via one adapter module. + NeMo-RL/TQ and vLLM are the first providers, not the design. + +### 1.1 The core principle: relocation, not invention + +The survey of this branch (2026-07-27) established that **token-in/token-out +already runs in production here** — routed through the most expensive +possible path: + +1. Gym's model server forces `logprobs=True, return_tokens_as_token_ids`, + string-parses generated ids from logprob entries, recovers prompt ids via + a second `/tokenize` HTTP call, and attaches + `prompt_token_ids`/`generation_token_ids`/`generation_log_probs` to the + response message (`responses_api_models/vllm_model/app.py:497-551`, + `nemo_gym/responses_converter.py:362-374`). +2. The agent echoes those arrays back inside its message history every turn. +3. The vLLM worker scrapes them (`model_post_init`, + `vllm_worker_async.py:505-517`) and splices the model's exact sampled ids + in front of the freshly rendered suffix (`_replace_prefix_tokens`, + `vllm_worker_async.py:52`). +4. The Ray return then carries all tokens again (`message_log` tensors + + decoded strings in `full_result`, `environments/nemo_gym.py:319-422`). + +Exact prefix conditioning, lineage identification, and template splicing are +therefore **proven code**. This design changes only custody: the cumulative +buffer moves from "echoed through the agent" to "held at the gate"; the +delta+logprobs move from "attached to HTTP responses and the Ray return" to +"staged once to TQ". Correctness properties are preserved *by construction* +(the model is conditioned on the same bytes as today), not re-verified after +the fact. + +### 1.2 Design alternatives + +| Design | Lineage mechanism | Token custody | Verdict | +|---|---|---|---| +| v2 doc | RL registry actor, hash-verified | worker→TQ | Works; two trackers; 2 RPCs/call | +| Hash-lineage draft | gate tree of hashes, worker hash-confirm | worker→TQ | Confirm not computable at depth ≥ 2 without extra wire fields; forks misresolve; verifies what token-in guarantees | +| **This doc** | **gate token buffer + message marker** | **gate (in-flight) + TQ** | Chosen: lineage explicit, zero verification on hot path | +| Bytes-through-gate | gate holds tokens + extras | gate | Rejected: logprobs/`routed_experts` (~KB/token) transit Python HTTP | +| Status quo | token echo through agent | agent messages + Ray return | The measured bytes problem | + +The hash machinery is not deleted from the universe — it returns in the +hardening phase (§ 10, H2) as finalize-time tamper evidence and as the +mechanism that later relaxes the strict serving rule (§ 3.3). + +## 2. Current state (what the survey established) + +Facts the plan depends on, with sources: + +- **SC path**: `_rollout_pump` → `RolloutManager.generate_and_push` + (`rollout_manager.py:644`) → `reserve` slot → `run_rollouts.remote` + (tokens ride the return) → `TQReplayBuffer.commit` tensorizes + puts N + rows (`replay_buffer.py:612-660`). `RolloutManager` runs *inside* the SC + actor; the only Ray boundary is `run_rollouts`. +- **No weight-version signal reaches vLLM workers** today; the only + fan-out is `RolloutManager.set_weight_version` + (`single_controller.py:591`). The `_sync_weights` drain is commented out + (`single_controller.py:571-584`). +- **vLLM workers are data-plane-unaware**: zero `data_plane` imports under + `models/generation/`. Template to copy: `sync_rollout_actor.py:128-130`. +- **`rollout_data` is never `register_partition`-ed**; lazy field + registration under concurrent puts is a documented TQ controller race + (`adapters/transfer_queue.py:449-461`). +- **Gym pin**: submodule `3rdparty/Gym-workspace/Gym` @ `610a08a` + (editable uv workspace member). It has **no gate and no capture + package** — in particular it predates upstream PR + [#2124](https://github.com/NVIDIA-NeMo/Gym/pull/2124) + (`nemo_gym/token_id_capture/`), which is a **required base** for the + Gym-side work (§ 9.2). The gate donor code (admission middleware, + `RolloutRegistry`, control router) lives in the prototype checkout's Gym + pin (`/lustre/fsw/.../gym/RL`, Gym @ `6ea5810`, + `nemo_gym/observability/capture_gate.py`). +- **Rollout identity today**: NeMo-RL passes no id into Gym (`_rowidx` + re-sort only); Gym↔vLLM affinity is a session cookie → sticky + round-robin (`vllm_model/app.py:576-584`). +- **Validity hook exists**: `calculate_baseline_and_std_per_prompt` + accepts a `valid_mask` currently hardwired to ones + (`advantage_estimator.py:69`). +- **Prototype donors** (`/lustre/fsw/.../gym/RL`): staging delta builder + + three-column TensorDict write, `compute_staging_digest` + (float32-bit-pattern scheme), hash-free mask-driven rebuild + (`StagedSnapshotTokenSource.entries()`), finalizer reconcile/verify + skeleton, gate admission + call-id mint + register/seal control API. + +## 3. The contract + +### 3.0 Protocol architecture: Gym defines, frameworks provide + +The integration varies along two axes (RL framework's storage/training; +inference backend) and is invariant along one (lineage custody, wire +schema, serving rule). The code mirrors that split: + +- **Gym owns the invariant, concretely**: the gate, the wire records + (single definition), the digest, the rebuild/linearize semantics, the + control routes, and the protocol definitions below. All of it lives in + the `nemo_gym/token_id_capture/` **leaf package** (grown from #2124), + under a hard purity rule — **no fastapi, no ray, no torch, no TQ + imports** in the core modules, enforced by an import-linter test — so + the package is importable inside any framework's worker process. +- **Gym also ships the backend adapters** (`adapters/vllm.py`, later + `adapters/sglang.py`) implementing a `CaptureAdapter` protocol: how to + enter prefix ids into an engine, splice the suffix, and extract + generated ids + logprobs. The gate itself is engine-blind. +- **The RL framework provides four small implementations** against Gym's + `protocols.py`: + +```python +# Defined in GYM (token_id_capture/staging/protocols.py); frameworks implement. +class TokenSink(Protocol): # WHERE deltas go (NeMo-RL impl: TQTokenSink) + def stage(self, record: StagedCallRecord) -> StageResult: ... + +class TokenSource(Protocol): # finalizer's read-back (NeMo-RL: TQ get_samples) + def fetch(self, staging_keys: list[str]) -> list[StagedCallSnapshot]: ... + +class WeightVersionProvider(Protocol): # trainer state, framework-owned + def __call__(self) -> int: ... + +# plus one wiring call at worker startup: +install_capture(serving_layer, sink=..., weight_version_fn=...) +``` + +Everything training-side (finalizer orchestration, placeholders, group +staleness, advantages) remains framework code — Gym has no opinion there. +Two rules make multi-framework work in practice: **staging keys are opaque +to Gym** (TQ keys, file paths, redis keys are all valid — the receipt +manifest is the only join between lineage and storage), and **conformance +is tested, not trusted** — Gym ships golden fixtures (call sequences → +byte-exact records/digests/manifests/linearized rows) that every framework +and adapter runs in its CI. `SCHEMA_VERSION` is negotiated at rollout +registration, so version skew fails at register time, not at finalize. + +**The whole contract at a glance** — everything above the line ships in +Gym; everything below is the entire surface an RL framework writes: + +``` +GYM nemo_gym/token_id_capture/ (leaf package; purity rule) + records.py StagedCallRecord, CommitCoords, RolloutReceipt, + CallRecord, staging_key(), SCHEMA_VERSION + protocols.py TokenSink, TokenSource, WeightVersionProvider, + CaptureAdapter; install_capture(...) + digest.py compute_staging_digest, encoders + lineage.py RolloutLineage — pure per-rollout state machine: + admit/commit/fail/seal -> manifest (no HTTP, no store; + separately tested; gate hosting stays thin) + capture.py RolloutTokenCapture.begin_call / complete_call — + engine-blind: record + digest build, fail-closed + stage->respond ordering, coords assembly + rebuild.py snapshots -> entries -> linearize(policy, terminal_hint) + adapters/vllm.py engine-specific ONLY: suffix splice, id+logprob + extraction, serving-layer hookup (sglang.py later) + store.py / memory_store.py #2124 store iface; in-memory buffer + conformance/ golden fixtures + installable test kit + gate thin hosting of lineage.py: admission, call_id mint, + marker resolve + fingerprint, serving rule, prefix + serving, coords ingestion, seal -> receipt; + control routes + RolloutControlClient +────────────────────────────────────────────────────────────────────────── +RL TQTokenSink / TQTokenSource # TQ impls of the protocols +RL blackbox_finalizer.py # orchestration over Gym rebuild +RL worker setup (once): install_capture(serving_layer, sink=…, + weight_version_fn=lambda: self._rollout_weight_version) +RL weight_version value (trainer state) + set_rollout_weight_version fan-out +RL control-plane calls via Gym's RolloutControlClient; buffer/setup wiring +``` + +### 3.1 Identity: rollout ids and the call marker + +- The SC mints rollout ids `{group_id}_g{i}` (matching existing TQ sample + ids, `payload.py:115`) and registers them at the gate (create-only) + before dispatch. Ids ride `responses_create_params.metadata` — the + zero-agent-change carrier already used for side-channel params + (`vllm_model/app.py:288-300`). +- The gate mints a `call_id` per admitted model call. +- **The marker.** When the gate forwards a completion to the agent, it + attaches `ng_call_id: ` to the assistant message — replacing + today's token-array attachment, same carrier, ~10 B instead of KBs. The + agent echoes history verbatim (this is how the token echo works today), + so the next request's messages carry the parent pointer **explicitly**. + Lineage is a dictionary lookup, not a content-matching tree walk: forks + (a sub-agent inheriting turn-1 history carries turn-1's marker) and + identical siblings (distinct markers) are resolved exactly. + +### 3.2 Wire changes per hop + +| Hop | Today | This design | +|---|---|---| +| agent → gate | messages + echoed token arrays (grows/turn) | messages + markers (token-free) | +| gate → worker | text prompt (+ echoed ids in messages) | `prefix_ids` + suffix messages via `extra_body`; or text mode (fallback) | +| worker → TQ | — | **the only heavy hop**: delta ids + logprobs + masks + extras, once/call | +| worker → gate | text + logprob block (ids string-parsed) + 2nd `/tokenize` call | text + delta ids (~4 B/token) + `CommitCoords` (~100 B); no `/tokenize` | +| gate → agent | text + token arrays | text + marker | +| gate → SC (`run_rollouts` return) | full token tensors + decoded strings | `RolloutReceipt` (~100 B/call, token-free) | +| finalizer ↔ TQ | — | staged rows in, canonical rows out (off hot path) | + +### 3.3 The serving rule (what makes zero-hash correct) + +> **Serve token-in only when the incoming request carries a unique, known +> marker AND the message history up to the marker matches the gate's +> recorded fingerprint for that call. Anything else — no marker, unknown +> marker, edited history — falls back to text mode: the worker renders the +> full conversation from scratch and the call is captured as a new root +> (full ids staged, `parent=None`).** + +The gate keeps a compact fingerprint (hash of normalized messages) per +committed call to detect history edits above the marker. A fallback is +wasteful (duplicated prefix storage, cold KV cache) but perfectly correct: +the model trains on exactly the bytes it saw. Silent wrong-prefix service is +structurally impossible — the gate serves only bytes whose provenance it +verified, or serves nothing. `token_in_rate` (§ 8) measures how often the +happy path holds. + +### 3.4 Records + +**`StagedCallRecord`** (worker → TQ, key `"{rollout_id}/{call_id}"`): +`token_ids_delta`, `token_mask_delta` (0.0 carried prompt / 1.0 generated), +`generation_logprobs_delta`, optional extras (`routed_experts`); tags: +`rollout_id, call_id, parent_call_id, prev_len, new_len, weight_version, +digest, schema_version`. + +**`CommitCoords`** (worker → gate, rides the response): `call_id, +parent_call_id, delta_len, cum_len, digest, staging_key, weight_version, +disposition: staged | capture_failed`, plus the delta ids for the gate's +buffer. + +**`RolloutReceipt`** (gate → SC at seal, token-free): `rollout_id, reward, +terminal_call_id, manifest: list[(call_id, parent_call_id|None, delta_len, +cum_len, digest, staging_key, weight_version, mode: token_in|text)], +schema_version`. + +All record shapes are defined **once**, in Gym's +`nemo_gym/token_id_capture/staging/records.py` (§ 3.0); frameworks import them +from the leaf package. Wire shapes freeze at the S1 gate. Hash fields +(`chain_hash`, `cum_hash`) are **reserved optional fields** so the +hardening layer (H2) is additive. + +### 3.5 Fail-closed ordering (per call) + +``` +gate: admit (marker → parent | fallback), mint call_id, + forward prefix_ids + suffix (or text) +worker: splice (or render), generate, extract ids+logprobs natively +worker: sink.stage(record) # bytes durable BEFORE ack + ok -> coords{staged} + delta ids ride the response + fail -> coords{capture_failed} +gate: ingest coords = authoritative commit; extend token buffer; + attach marker; forward text to agent +``` + +A child request cannot exist before its parent's bytes are durable and +committed, because the marker the child needs rides the response the gate +releases only after ingesting coords. Capture failure does not break the +agent: the completion still returns; the gate marks the rollout +capture-poisoned; the finalizer produces a placeholder. +`token_capture.on_capture_failure: continue | abort` (default `continue`). + +## 4. Data flow + +``` +SC _rollout_pump + └─ generate_and_push(prompt, target_step) + ├─ tq_buffer.reserve(weight_version=v_start) (unchanged) + ├─ mint N rollout_ids, register at gate (create-only) (new) + ├─ NemoGym.run_rollouts.remote(rows + rollout_ids) (token-free) + │ + │ per model call: + │ agent ─(messages + markers)─► GATE + │ marker → parent lookup; fingerprint check; + │ mint call_id; prefix_ids from token buffer + │ GATE ─(prefix_ids + suffix | text)─► vLLM WORKER + │ splice (_replace_prefix_tokens) | full render + │ generate; extract ids+logprobs natively + │ sink.stage(record) ──► TQ rollout_staging ◄── the only + │ delta ids + coords ride the response heavy hop + │ GATE ingests coords = COMMIT; buffer += delta; + │ marker on assistant message; text to agent + │ + ├─ seal each rollout → RolloutReceipt; gate drops buffer + state + ├─ finalize group: fetch rows by manifest keys → digest check → + │ mask-driven rebuild → linearize(main_chain_only, + │ terminal_hint) → N rows (placeholders as needed) → + │ put_samples(rollout_data) + └─ tq_buffer.commit_finalized(group_id, meta, group_min_wv, group_max_wv) + +SC _train_pump: unchanged; baseline over valid rows (§ 7) +SC _sync_weights: rotates worker weight_version (§ 6) +``` + +Two TQ partitions: `rollout_staging` (delta rows, cleared by finalizer / +eviction / TTL) and the existing `rollout_data` (canonical rows). Both are +pre-registered at setup (§ 2, controller race). + +### 4.1 Worked example + +Group `g7`, rollout `g7_r0`, wv 4 throughout. **c1**: no marker → text mode, +new root; worker renders `[10..14]` (3 prompt + 2 generated), stages +`g7_r0/c1`, coords + delta ids back; gate buffers, marks the assistant +message `ng_call_id=c1`. **c2** (tool result): messages carry `c1`'s marker +→ fingerprint ok → token-in: `prefix_ids=[10..14]` + suffix `[tool:"391"]`; +worker splices `[20,21,22]`, generates `[23,24]`; stages delta of 5; +`parent=c1`. **c3** (sub-agent from turn-1 history): carries `c1`'s marker → +token-in from an *interior* node — a fork, resolved exactly. **c4** +(framework rewrote a message): fingerprint miss → text mode, new root; 9 ids +staged, `parent=None`. Seal → receipt manifest `[(c1,∅,5),(c2,c1,+5), +(c3,c1,+4),(c4,∅,9)]`, terminal `c2`, reward 1.0. Finalize: fetch 4 rows, +digest-check, rebuild main chain c1→c2 → one canonical row (10 ids, 4 +trainable), c3/c4 verified-untrained; publish N rows; clear staging. + +## 5. What the finalizer verifies (and what it doesn't) + +Per row: digest recomputation (`compute_staging_digest` over ids + mask + +logprob bit patterns — catches TQ corruption and key mixups), shape/mask/ +finite-logprob checks, `prev_len + delta_len == cum_len`, weight-version tag +equality. Rebuild is the prototype's **hash-free, mask-driven** +`StagedSnapshotTokenSource.entries()`; linearization +`main_chain_only` with `terminal_hint`. Any rejection → masked placeholder +(always N rows; `prompt_ids_for_adv` copied from a valid sibling; +`min_valid_fraction_per_group` optionally drops the group). + +Not verified in the MVP: cross-row chain integrity (an adversarial reorder +of manifest entries that also fixes up lengths). The gate is inside the +trust boundary (network-isolated gate→worker hop, as v2 § 4.6); chain +hashes return as tamper evidence in H2. + +## 6. Weight versions, refit, staleness + +Inherited from v2 § 4.4: per-call tagging via the worker's +`_rollout_weight_version` (new attribute; set at the end of both refit +paths and via a new `set_rollout_weight_version` fan-out from +`_sync_weights`); group staleness = oldest call version (`group_min_wv`), +stored as the slot's effective version (`commit_finalized`); +`mixed_weight_version_policy: allow | reject`; the T1 atomic-rotation TODO +unchanged and still prerequisite for strict modes; verl's work-preserving +`wait` option on the hardening list. MVP matrix: `staleness_window` + +`allow` only; strict modes raise `NotImplementedError`. Note the SC drain +is currently commented out (`single_controller.py:571-584`) — straddles are +normal and absorbed by `group_min_wv` conservatism. + +## 7. Failure model + +| Failure | Consequence | Recovery | +|---|---|---| +| Worker stages, dies before responding | Gate call-timeout → call failed → no marker released → rollout cannot continue → placeholder | Staging TTL sweeps the orphan row | +| Worker responds, gate dies | Rollout dies (gate mediates it); no receipt | Staging TTL; SC dispatch timeout | +| Gate dies between seal and receipt delivery | Receipt rides the `run_rollouts` return; if lost, rollout unrecoverable → placeholder + TTL | Optional receipt persistence (H1) | +| Coords lost (response dropped) | Call-timeout → failed; agent never got completion → no child exists | TTL | +| Agent strips/edits markers | Fingerprint or marker miss → text fallback, new root | Correct but wasteful; visible as `token_in_rate` drop | +| SC dispatch cancelled / shutdown | `try/finally`: `fail_rollout` + clear staged keys by prefix + release buffer permit | Registration TTL backstop | +| NaN-logprob batch retry | Would re-register create-only ids | `rollout_max_attempts_to_avoid_lp_nan == 1` enforced at setup | + +Cleanup is two stores: the SC slot (+ its TQ rows, staging + canonical) and +the gate's per-rollout state (self-clears at seal / `fail_rollout` / +registration TTL). Slots record their rollout_ids at reserve time; +`TQReplayBuffer.remove(remove_in_dp=True)` clears both partitions. + +## 8. Metrics + +`token_in_rate` (marker hit), `fallback_rate` by cause (no-marker / +fingerprint-miss / unknown-marker), `capture_failure_rate`, +`digest_verify_failures`, `invalid_row_rate`, finalize p50/p99, `wv_spread`, +gate admission→commit latency, receipts lost, staging partition size, +per-call HTTP bytes (the headline number vs. the echo path). + +## 9. Component changes + +### 9.0 Runtime placement at a glance + +Who runs where, and the one-line ownership rule for each home: + +| Runtime home | Components | Owns | +|---|---|---| +| **SingleController Ray actor** (NeMo-RL) | `_rollout_pump`/`_train_pump`/`_sync_weights`; `RolloutManager` (mints rollout_ids); `TQReplayBuffer` (`reserve`/`commit_finalized`/`remove`); `BlackboxFinalizer` (runs in the dispatch task via `asyncio.to_thread` for the MVP); `StalenessSampler`; advantage pump | **Training assembly**: group semantics, slots, receipts → N canonical rows, staleness, cleanup | +| **NemoGym Ray actor** (NeMo-RL file wrapping Gym) | server spin-up; token-free `run_rollouts` + receipt unpacking; gate control-plane client (register/seal/`fail_rollout`) | The Ray↔HTTP boundary; no token logic | +| **Gym model server = the gate** (submodule fork = main + #2124 + gate work) | thin hosting of the pure **`lineage.py`** state machine; admission + call_id mint + TTLs; per-rollout **token buffer** (in-memory `token_id_capture` store impl); `ng_call_id` marker attach/resolve + history fingerprint; `prefix_ids` serving + rollout→worker affinity; coords ingestion = commit; seal → receipt | **Lineage custody**: everything that requires understanding *messages*. Holds token ids in flight; never logprobs; never writes TQ | +| **Gym agent + resources servers** | — | **Nothing new** (design goal: 27 agent impls untouched; markers ride messages opaquely; rewards via `/verify` as today) | +| **vLLM worker Ray actor** (NeMo-RL, hosting Gym's capture) | in-process HTTP server; **Gym `capture.py`** (engine-blind: record/digest build, fail-closed ordering, coords) + **Gym `adapters/vllm.py`** (splice, extraction) via `install_capture`; NeMo-RL provides `TQTokenSink.stage()` (the only heavy hop), the DP client, and `_rollout_weight_version` | **Token production + durability**: capture logic is Gym's; storage and hosting are NeMo-RL's; bytes durable before ack | +| **TransferQueue** | `rollout_staging` (finalizer is the only reader) + `rollout_data` (train pump is the only reader) | Bytes at rest | + +The wire records, digest, rebuild semantics, and protocols are defined +**once**, in Gym's dependency-free `token_id_capture` leaf package +(§ 3.0), and imported by both the gate and the framework's worker/finalizer +— importable anywhere because the core modules carry no heavy dependencies +(enforced in Gym CI). + +### 9.1 NeMo-RL + +There is **no** `nemo_rl/experience/token_capture/` package — records, +digest, protocols, rebuild, and capture logic live in Gym (§ 3.0, § 9.2). +NeMo-RL writes only the provider implementations and training assembly: + +| Component | Change | +|---|---| +| `nemo_rl/data_plane/tq_token_sink.py` (new) | implements Gym's `TokenSink` and `TokenSource` protocols over TQ (`put_samples` / `get_samples`); the only hot-path file that knows TQ | +| `nemo_rl/experience/blackbox_finalizer.py` (new) | orchestration only: fetch via `TokenSource`, call Gym's verify/`rebuild`/`linearize`, always-N placeholders, `group_min_wv`, publish to `rollout_data` | +| `algorithms/async_utils/replay_buffer.py` | `commit_finalized`; slots record rollout_ids; `remove` clears staging; `abort(group_id)`; fix `commit` on evicted slots (`:657`) | +| `algorithms/single_controller.py` | release `_buffer_capacity` in dispatch `finally` (`:319`); `set_rollout_weight_version` fan-out at `:591`; teardown sweep; metrics | +| `algorithms/single_controller_utils/setup.py` | pre-register `rollout_staging` + `rollout_data`; gate config into `spinup_nemo_gym_actor`; sink factory + `dp_cfg` to generation setup | +| `algorithms/single_controller_utils/config.py` | `TokenCaptureConfig` on `MasterConfig`; `AsyncRLConfig` additions | +| `models/generation/vllm/vllm_worker_async.py` | **hosting only**: one `install_capture(serving_layer, sink=TQTokenSink(...), weight_version_fn=...)` call at startup; `setup_token_capture(dp_cfg)` fan-out target building the in-worker DP client; `_rollout_weight_version` attribute. Capture logic moves to Gym: fail-closed ordering + record build in `capture.py`; prefix-in, splice (`_replace_prefix_tokens` relocates), extraction in `adapters/vllm.py` | +| `models/generation/vllm/vllm_generation.py` | `setup_token_capture` / `set_rollout_weight_version` fan-outs (existing `run_all_workers_single_data` pattern) | +| `experience/rollout_manager.py` | mint rollout_ids (thread `group_id` into `run_rollout`); receipt mode in `_result_to_completion` / `_compute_rollout_metrics` (incl. removing tokens from the wandb table, `:575`) | +| `environments/nemo_gym.py` | register/seal/fail control-plane helpers; receipt-mode `_postprocess` (drop token walk + contiguity assert `:329-388` — the gate owns that guarantee now); fix `run_rollouts` return annotation; NaN-retry hard error | +| `algorithms/advantage_estimator.py` | pass real validity into `calculate_baseline_and_std_per_prompt` (`:69`); validity folds into `sample_mask` (no new train field) | + +### 9.2 Gym (vendored submodule, fork branch **based on #2124**) + +The Gym implementation builds **on top of upstream PR #2124** (token id +capture core, `nemo_gym/token_id_capture/`), not beside it. The fork branch +is upstream main + #2124 (pinned to a specific rev of that PR) + the gate +work. What #2124 supplies and how it is used: + +- `records.py` `TokenEntry` (rollout id + server call id + prompt/gen ids + + logprobs + message content) → the gate's per-call buffer entry; this + design adopts its rollout/call-id grammar rather than minting a parallel + one. +- `sink.py` (records a `TokenEntry` from the finished model-server + response, streaming-safe) → the coords-ingestion point: extended to read + the worker's delta ids + `CommitCoords` and extend the rollout buffer. +- `store.py` (`TokenCaptureStore`, per-rollout JSONL, per-file locking) → + becomes the store interface behind the gate buffer: a new in-memory + implementation serves the hot path; the JSONL store is retained as an + optional debug/persistence backend and for H1 receipt persistence. +- `config.py` (`token_id_capture_enabled` + directory) and the + `base_responses_api_model.py` integration (record + install routes + + re-stream) → the on/off switch and wiring the gate extends. +- `routes.py` (`GET /ng-capture/tokens/{rollout_id}`) → retained; useful + as a debug read path beside TQ staging. + +The package is grown into the **integration SDK** under the § 3.0 purity +rule (core modules dependency-free, import-linter-enforced), so any +framework's worker can import it: + +| Component | Change | +|---|---| +| `nemo_gym/token_id_capture/` (from #2124) | base package: records/store/sink/config/routes as above; in-memory store impl added | +| `token_id_capture/staging/records.py` (new) | **single definition** of all wire shapes (§ 3.4), beside #2124's `TokenEntry` (whose `records.py` is untouched); `SCHEMA_VERSION` | +| `token_id_capture/staging/protocols.py` (new) | `TokenSink`, `TokenSource`, `WeightVersionProvider`, `CaptureAdapter`; `install_capture` entrypoint | +| `token_id_capture/staging/digest.py` (new) | `compute_staging_digest` + encoders (prototype `rollout_writer.py:1014` port; golden vectors) | +| `token_id_capture/staging/rebuild.py` (new) | pure functions: snapshots → entries → `linearize(policy, terminal_hint)` — identical training-row semantics for every framework (prototype `staged_token_source.py` core) | +| `token_id_capture/staging/lineage.py` (new) | `RolloutLineage` — pure per-rollout state machine (admit/commit/fail/seal → manifest); no HTTP, no store; unit-tested standalone at S1 | +| `token_id_capture/staging/capture.py` (new) | `RolloutTokenCapture.begin_call`/`complete_call` — engine-blind: record + digest build, fail-closed stage→respond ordering, coords assembly; tested against mock adapter + mock sink | +| `token_id_capture/adapters/vllm.py` (new) | engine-specific only: prefix-in entry, suffix splice (relocated `_replace_prefix_tokens`), native id+logprob extraction, serving-layer hookup. `adapters/sglang.py` is a later drop-in that inherits `capture.py`'s ordering for free | +| `token_id_capture/staging/conformance/` (new) | golden fixtures + installable test kit run by every framework/adapter CI | +| gate hosting (port from prototype `capture_gate.py`, `rollout_registry.py`) | **thin hosting of `lineage.py`**: admission + call-id mint, marker resolve + fingerprint, serving rule, coords ingestion, seal → receipt, `fail_rollout`/TTL; control router; Gym also ships the `RolloutControlClient` frameworks call | +| `responses_api_models/vllm_model/app.py` | per-rollout **token buffer**; marker → parent lookup + fingerprint check in `_preprocess_chat_completion_create_params` (`:259`); `prefix_ids` into `extra_body`; coords ingestion replacing the logprob-scrape + `/tokenize` block (`:497-551`); rollout affinity in `_resolve_client` (`:576`) | +| `nemo_gym/responses_converter.py` | attach `ng_call_id` marker instead of token arrays (`:362-374`) | +| rollout id plumbing | `responses_create_params.metadata` carrier end-to-end; no agent changes | + +**Gym dependency:** a fork branch of the submodule = upstream main + +**#2124 (pinned rev)** + the gate work; the gitlink must point at a rev +fetchable by CI (decision at the S1 gate: fork remote vs. NVIDIA-NeMo/Gym +branch). Because #2124 is adopted as the base, H4 upstreaming reduces to +contributing the gate/TQ layers and reconciling with the *rest* of the +stack (#2125–#2128). + +### 9.3 File manifest + +New files, **Gym fork** (base = main + #2124; all under the § 3.0 purity +rule except `adapters/` and the gate/server wiring): + +| File | Defines | Stage | +|---|---|---| +| `nemo_gym/token_id_capture/staging/records.py` | single wire schema (§ 3.4): `StagedCallRecord`/`CommitCoords`/receipt/manifest; `SCHEMA_VERSION` (#2124's `records.py` untouched) | S1 | +| `nemo_gym/token_id_capture/staging/protocols.py` | `TokenSink`, `TokenSource`, `WeightVersionProvider`, `CaptureAdapter`, `install_capture` | S1 | +| `nemo_gym/token_id_capture/staging/digest.py` | `compute_staging_digest` + encoders (prototype port; golden vectors) | S1 | +| `nemo_gym/token_id_capture/staging/lineage.py` | `RolloutLineage` pure state machine: admit/commit/fail/seal → manifest (no HTTP, no store) | S1 | +| `nemo_gym/token_id_capture/staging/rebuild.py` | snapshots → entries → `linearize(policy, terminal_hint)` (pure; prototype `staged_token_source.py` core) | S1 | +| `nemo_gym/token_id_capture/staging/conformance/` | golden fixtures + installable conformance kit | S1 | +| `nemo_gym/token_id_capture/staging/capture.py` | `RolloutTokenCapture` — engine-blind capture: record/digest build, fail-closed stage→respond ordering, coords assembly | S2 | +| `nemo_gym/token_id_capture/adapters/vllm.py` | engine-specific: prefix-in entry, suffix splice (relocated `_replace_prefix_tokens`), id+logprob extraction, serving-layer hookup | S2 | +| `nemo_gym/token_id_capture/memory_store.py` | in-memory rollout token buffer behind #2124's store interface | S3 | +| `nemo_gym/token_id_capture/gate.py` | thin hosting of `lineage.py`: admission, call_id mint, marker resolution + fingerprint, serving rule, receipt assembly | S3 | +| `nemo_gym/token_id_capture/control_routes.py` | register/seal/`fail_rollout` control API + `RolloutControlClient` | S3 | + +Modified, Gym fork: `responses_api_models/vllm_model/app.py` +(marker lookup + `prefix_ids` in `_preprocess…`; coords ingestion replacing +the logprob-scrape + `/tokenize`; affinity in `_resolve_client`; S3), +`nemo_gym/responses_converter.py` (marker instead of token arrays; S3), +`nemo_gym/base_responses_api_model.py` (install gate + routes; S3), +`nemo_gym/global_config.py` (config keys; S3) — details in § 9.2. + +New files, **NeMo-RL** (provider implementations + training assembly only): + +| File | Defines | Stage | +|---|---|---| +| `nemo_rl/data_plane/tq_token_sink.py` | `TQTokenSink` / `TQTokenSource` implementing Gym's protocols over `put_samples`/`get_samples` | S1 | +| `nemo_rl/experience/blackbox_finalizer.py` | orchestration over Gym verify/`rebuild`/`linearize`; `finalize_group` (always N rows, placeholders, `group_min_wv`) | S4 | + +Modified, NeMo-RL: `algorithms/async_utils/replay_buffer.py` (S1), +`algorithms/single_controller_utils/config.py` (S1), `.../setup.py` +(S1+S4), `algorithms/single_controller.py` (S1 fix + S4), +`models/generation/vllm/vllm_worker_async.py` (S2, hosting only), +`models/generation/vllm/vllm_generation.py` (S2, fan-outs), +`environments/nemo_gym.py` (S3-RL+S4), `experience/rollout_manager.py` +(S4), `algorithms/advantage_estimator.py` (S4), exemplar YAML +`examples/configs/grpo_math_1B_single_controller.yaml` (S4) — details in +§ 9.1. + +Placement rule: protocols, records, digest, rebuild, and capture logic are +defined once in Gym's leaf package and imported everywhere (venv check at +the S1 gate); NeMo-RL contributes storage implementations, hosting, and +training assembly. Another RL framework integrates by re-implementing only +the two NeMo-RL "new files" rows; another backend by one `adapters/` file. + +## 10. Implementation plan + +### MVP — one PR, five sign-off-gated stages + +Single branch, one PR; each stage a signed-off commit series keeping the +tree green (S1–S3 dormant behind `token_capture.enabled=false`); each ends +at a review gate (stage diff, test results, deviations presented for +explicit sign-off). **Wire shapes (§ 3.4) and the serving rule (§ 3.3) +freeze at the S1 gate.** + +- **S1 — primitives (Gym fork) + buffer surgery (RL repo).** Gym fork: + `token_id_capture` records (single wire schema), `protocols.py`, + `digest.py` (golden vectors vs. prototype), **`lineage.py`** (pure state + machine), `rebuild.py`, conformance kit, import-linter purity test. RL: + `TQTokenSink`/`TQTokenSource` implementing the protocols; + `TokenCaptureConfig`; `TQReplayBuffer` `commit_finalized` / rollout_ids + on slots / staging-aware `remove` / `abort` / evicted-slot fix; + `_buffer_capacity` leak fix; partition pre-registration. Unit tests: + records/digest vectors; **lineage state machine standalone** (admit/ + commit/fail/seal transitions, manifest ordering, TTL/fail paths, fork + topologies) — lineage logic is fully tested two stages before it + touches HTTP; conformance kit green on the TQ implementations; buffer + ops incl. eviction/cleanup. + **S1-gate checklist:** submodule fork logistics decided; the leaf + package importable in the vLLM worker venv; vLLM prefix-ids path + + splice validated for the functional-test templates. +- **S2 — capture core + vLLM adapter (Gym fork) + worker hosting (RL + repo).** Gym, two layers: **`capture.py`** — engine-blind + `RolloutTokenCapture` (record + digest build, fail-closed stage→respond + ordering, coords + delta ids on the response, non-streaming assert), + tested against a **mock adapter + mock sink** so the ordering matrix is + backend-independent; **`adapters/vllm.py`** — engine-specific only: + `extra_body` prefix-in feeding the relocated `_replace_prefix_tokens` + splice, native id+logprob extraction, serving-layer hookup, with its own + per-template splice goldens. RL: `install_capture` call at worker + startup, DP client + `setup_token_capture` fan-out, + `_rollout_weight_version` + `set_rollout_weight_version` fan-out; + hosting/fan-out/version-stamping tests. +- **S3 — Gym gate (submodule fork, based on #2124).** Rebase the fork onto + upstream main + #2124 (pinned rev; run its 20-test capture suite as the + base sanity check). **Host the S1 `lineage.py` machine in the gate** — + no new lineage logic lands here, only hosting: in-memory store impl, + admission + call-id mint ports (prototype donors), marker attach/resolve + + fingerprint, the serving rule, prefix serving, coords ingestion via + the #2124 sink seam, rollout affinity, token-free receipts, TTLs, + control routes + `RolloutControlClient`. Conformance tests: the S1 + golden call sequences replayed **through the gate** → manifests + byte-identical to S1's direct-drive results; marker-stripped and + history-edited fallbacks; duplicate-coords / wrong-rollout rejection; + timeout; #2124 suite stays green. +- **S4 — receipts, finalizer, SC integration.** Receipt-mode + `run_rollouts` (tokens removed from message_log, `full_result`, wandb + table); `blackbox_finalizer` + `finalize_group` (always N rows, + placeholders, `group_min_wv`/`group_max_wv`, + `min_valid_fraction_per_group`); validity-aware baseline (unit-tested); + config validation (MVP matrix only); setup wiring; `commit_finalized` + + cleanup; teardown sweep; NaN-retry hard error; metrics (§ 8). Gate + evidence: 2-GPU manual run with a sub-agent fork → two-root manifest → + trained main chain. +- **S5 — verification.** Fixed-seed job on legacy and capture paths, + training rows dumped from TQ and diffed offline (token-in should be + byte-identical where the legacy echo path drifts); reward-curve + comparison; per-call HTTP bytes measured vs. the echo path; chaos smoke + (kill gate mid-step → placeholders + TTL, no leaks); capture-enabled + functional test in `L1_Functional_Tests_SingleController.sh`. + S5 sign-off = MVP acceptance. + +### Hardening (ordered) + +- **H1 — failure sweep + chaos.** Gate death mid-step, coords loss, + receipt loss; optional receipt persistence if S5 measures meaningful + loss; kill-gate CI test. First, because bring-up debugging kills actors. +- **H2 — hash layer.** `cum_hash`/`chain_hash` fill the reserved record + fields: chain re-verification at finalize (tamper evidence) and + worker-side prefix confirm — which relaxes the strict serving rule + (uncertain marker → one hash check instead of a full-render new root). +- **H3 — atomic weight-version rotation** (v2 § 4.4 TODO) then **strict + modes**: `strict_on_policy` (drain re-enabled), `reject`, `wait` + (verl's dropless pattern), `force_in_order`. +- **H4 — upstream into Gym proper.** With the § 3.0 structure the code is + already in its final home: upstreaming is merging the fork branch onto + the merged #2124 and reconciling with the remainder of the stack (#2125 + trajectory builder, #2126 delivery/scoping, #2127 on-policy pin, #2128 + example); publish the conformance kit as the multi-framework contract. +- **H5 — perf + scale.** Incremental suffix tokenization (drop the double + render); finalizer isolation/pool; admission caps (calls/rollout, buffer + bytes/rollout — the design's unbounded resources); gate scale-out with + rollout affinity; SGLang adapter. + +**Post-MVP validation:** 1-off async nightly in capture mode; perf report +reproducing the sync prototype measurements (HTTP bytes/token, step time) +plus `token_in_rate` and gate latency. + +## 11. Risks + +- **Gym submodule fork on the MVP critical path.** Mitigations: donor gate + code is proven (prototype `6ea5810`); the fork is ours; the gitlink/CI + question is forced at the S1 gate, not discovered late. +- **#2124 is an open PR.** Basing the fork on it means rebase churn if it + changes before merging. Mitigations: pin the fork to a specific #2124 + rev; keep gate code in separate modules touching the base package only + through its public seams (records/store/sink/config), so a rebase is + mechanical; track the PR during S3. +- **Protocols in the fork raise iteration friction**: every schema/protocol + change during bring-up touches the Gym fork even for RL-only work. + Mitigated by the fork being a local editable workspace member (no + publish cycle) and by freezing shapes at the S1 gate. +- **Leaf-package availability in worker venvs.** The purity rule makes the + import safe, but each framework's worker environment must actually + contain `nemo_gym` (or a separately published leaf distribution). + Checked at the S1 gate for NeMo-RL's vLLM `py_executable`. +- **Marker survival across agent frameworks.** The marker uses the exact + carrier today's token echo uses, so it survives wherever the current + pipeline works; an agent that strips unknown fields degrades to text + fallback — correct but wasteful. `token_in_rate` is first-class from S4. +- **Gate as stateful hot-path service** (per-rollout token buffers, KBs–MBs + × in-flight rollouts). Buffer bytes are bounded by H5 caps; state + self-clears at seal/TTL; crash blast radius measured in S5 chaos; and + the lineage state machine is a pure, separately-tested class + (`lineage.py`, S1), so gate hosting stays thin. +- **No cross-row chain integrity in the MVP** (§ 5): accepted; the gate is + inside the existing trust boundary; H2 restores tamper evidence. +- **Fingerprint definition** (message normalization for equality) must be + pinned in S3 conformance tests — too strict inflates fallbacks, too loose + misses edits. Fallback-on-mismatch keeps both errors safe. +- **Finalize latency, placeholder-heavy groups, checkpointing**: unchanged + from v2 § 8 (in-flight rollouts abandoned on restore; TTL + create-only + registration make this safe). + +## Appendix A — prior art + +- **verl**: token-in/token-out rationale ("apply_chat_template to final + history makes PPO not converge"); TQ meta-passing; `global_steps` spans + + `drop|wait` staleness policies. No forest — linear trajectories only. +- **slime** (commit `ea9819f`): message-tree lineage with prefix-match + + rewrite-merge; consistent-hash session→engine affinity + (`X-SMG-Routing-Key`) mirrored by this design's rollout affinity. The + earlier drafts adopted its mount-point walk as a lineage hint; this + design replaces content inference entirely with the explicit marker — + the failure modes slime papers over (ambiguity, rewrites) become + explicit fallbacks here. +- **Gym #2124–#2128**: token-id capture stack for external-agent training + (issue #1824). **#2124 (capture core: records/store/sink/config/routes) + is the adopted base for this design's Gym work** (§ 9.2); it has no + gate/lineage/prefix-serving surface — that is what this design adds on + top. #2125–#2128 (trajectory builder, delivery/scoping, on-policy pin, + example) are reconciled at H4. +- **The sync prototype** (`/lustre/fsw/.../gym/RL`, branch + `pranav/tq_gym_prototype`): proved the staging dataflow and the perf + numbers (−46.9 % HTTP bytes/token, −55.7 % exchanges, −4.3 % step time + p50); donor for the digest scheme, staging sink, finalizer skeleton, and + the gate's admission/control plane. diff --git a/docs/index.md b/docs/index.md index 92f2989eb20..6446c31f4f9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -325,6 +325,9 @@ design-docs/training-backends.md design-docs/sequence-packing-and-dynamic-batching.md design-docs/env-vars.md design-docs/nemo-gym-integration.md +design-docs/tq-gym-async-single-controller.md +design-docs/tq-gym-gate-authoritative.md +design-docs/tq-gym-gate-authoritative-implementation-log.md ``` ```{toctree} diff --git a/nemo_rl/algorithms/async_utils/replay_buffer.py b/nemo_rl/algorithms/async_utils/replay_buffer.py index 10975aac286..ecc6958e992 100644 --- a/nemo_rl/algorithms/async_utils/replay_buffer.py +++ b/nemo_rl/algorithms/async_utils/replay_buffer.py @@ -25,6 +25,7 @@ from nemo_rl.data_plane import KVBatchMeta from nemo_rl.experience.interfaces import PromptGroupRecord from nemo_rl.experience.payload import pack_payload, record_to_train_batch +from nemo_rl.experience.row_dump import maybe_dump_train_rows # Classes with @ray.remote can't be inherited from, so we split the implementation out. @@ -659,6 +660,13 @@ async def commit( sample_ids, fields, tags = pack_payload( train_batch, weight_version=start_weight_version, group_id=group_id ) + maybe_dump_train_rows( + source="legacy_commit", + group_id=group_id, + sample_ids=list(sample_ids), + train_batch=train_batch, + weight_version=start_weight_version, + ) await self._call_dp( "put_samples", sample_ids=sample_ids, diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 33dceeb0004..3e042857f0a 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -549,6 +549,8 @@ async def _train_pump(self) -> None: self._logger.log_metrics( timing_metrics, step=self._train_steps, prefix="timing/train" ) + if self._master_config.token_capture.enabled: + await self._log_gate_metrics() self._timer.reset() # min sample version refers to the version each consumed sample was @@ -603,6 +605,29 @@ async def _sync_weights(self) -> None: ) self._rollout_permitted.set() + async def _log_gate_metrics(self) -> None: + """Log the capture gate's cumulative § 8 counters + token_in_rate. + + Counters are cumulative over the run; ``gate/token_in_rate`` is the + cumulative marker-hit rate over all admitted model calls. Fetch + failures are logged and swallowed — metrics must never kill a step. + """ + try: + counters = await self._rollout_manager.gate_metrics() + except (RuntimeError, OSError) as error: + print(f"gate metrics fetch failed: {error}", flush=True) + return + if not counters: + return + calls = counters["token_in"] + sum( + v for k, v in counters.items() if k.startswith("fallback_") + ) + gate_metrics: dict[str, float] = {k: float(v) for k, v in counters.items()} + if calls: + gate_metrics["token_in_rate"] = counters["token_in"] / calls + self._logger.log_metrics(gate_metrics, step=self._train_steps, prefix="gate") + print(f"gate_metrics={gate_metrics}", flush=True) + async def _advantage_pump(self, meta: KVBatchMeta) -> KVBatchMeta: """Fetch advantage inputs, compute advantages, and write them back. diff --git a/nemo_rl/environments/nemo_gym.py b/nemo_rl/environments/nemo_gym.py index fd984cb885d..b80a98be9df 100644 --- a/nemo_rl/environments/nemo_gym.py +++ b/nemo_rl/environments/nemo_gym.py @@ -16,6 +16,7 @@ from pathlib import Path from typing import Any, Dict, List, NotRequired, Optional, TypedDict +import aiohttp import ray import torch from ray.util.scheduling_strategies import NodeAffinitySchedulingStrategy @@ -368,7 +369,17 @@ async def run_rollouts( nemo_rl_results = [] for task in nemo_gym_result_iterator: with timer.time(label=f"{timer_prefix}/await_results"): - nemo_gym_row, nemo_gym_result = await task + try: + nemo_gym_row, nemo_gym_result = await task + except aiohttp.ClientResponseError as e: + # aiohttp exceptions carry CIMultiDictProxy headers + # that Ray cannot pickle across the actor boundary, + # masking the real error with a TypeError; re-raise + # as a plain, picklable RuntimeError. + raise RuntimeError( + f"NemoGym rollout HTTP error: {e.status} " + f"{e.message} url={e.request_info.real_url}" + ) from None with timer.time(label=f"{timer_prefix}/postprocess_results"): if self._token_capture_enabled: diff --git a/nemo_rl/experience/blackbox_finalizer.py b/nemo_rl/experience/blackbox_finalizer.py index 04a48863a47..b59d96c73a2 100644 --- a/nemo_rl/experience/blackbox_finalizer.py +++ b/nemo_rl/experience/blackbox_finalizer.py @@ -39,6 +39,7 @@ from nemo_rl.data_plane import KVBatchMeta from nemo_rl.data_plane.tq_token_sink import TQTokenSink, TQTokenSource from nemo_rl.experience.payload import pack_payload +from nemo_rl.experience.row_dump import maybe_dump_train_rows @dataclass(frozen=True) @@ -313,6 +314,13 @@ def finalize_group( sample_ids, fields, tags = pack_payload( train_batch, weight_version=group_min_wv, group_id=group_id ) + maybe_dump_train_rows( + source="finalizer", + group_id=group_id, + sample_ids=list(sample_ids), + train_batch=train_batch, + weight_version=group_min_wv, + ) assert sample_ids == rollout_ids, ( "canonical sample ids must equal the gate-registered rollout ids: " f"{sample_ids} != {rollout_ids}" diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index 4db6efc61fe..c9b0c42067b 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -708,6 +708,19 @@ def set_weight_version(self, version: int) -> None: """ self._weight_version = int(version) + async def gate_metrics(self) -> Optional[dict[str, int]]: + """Fetch the capture gate's § 8 counters, or None off the capture path. + + Returns: + Cumulative gate counters (token_in, fallback_*, capture_failed, + registered/sealed/failed/expired) from ``/ng-control/metrics``, + or None when no NemoGym env handle is wired. + """ + env = self._env_handles.get("nemo_gym") if self._env_handles else None + if env is None: + return None + return await env.gate_metrics.remote() + async def run_rollout( self, input_sample: DatumSpec, *, rollout_ids: Optional[list[str]] = None ) -> PromptGroupRecord: diff --git a/nemo_rl/experience/row_dump.py b/nemo_rl/experience/row_dump.py new file mode 100644 index 00000000000..12b831a6e11 --- /dev/null +++ b/nemo_rl/experience/row_dump.py @@ -0,0 +1,77 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""Env-gated dump of canonical training rows at their TQ publish sites. + +Set ``NRL_SC_DUMP_TRAIN_ROWS=`` to append one JSON line per training row +whenever a group is published to the ``rollout_data`` partition — from the +legacy ``TQReplayBuffer.commit`` path and from the token-capture +``BlackboxFinalizer`` publish. Off (no I/O, no imports of the payload) unless +the env var is set. Used by the S5 legacy-vs-capture offline row diff. +""" + +import json +import os +import threading +from collections.abc import Mapping +from typing import Any, Optional + +import torch + +_DUMP_ENV_VAR = "NRL_SC_DUMP_TRAIN_ROWS" +# The finalizer publishes from a worker thread (asyncio.to_thread) while the +# legacy path publishes from the SC event loop; serialize appends. +_G_WRITE_LOCK = threading.Lock() + + +def _row_value(tensor: torch.Tensor, row: int) -> Any: + value = tensor[row] + if value.dim() == 0: + return value.item() + return value.tolist() + + +def maybe_dump_train_rows( + *, + source: str, + group_id: str, + sample_ids: list[str], + train_batch: Mapping[str, torch.Tensor], + weight_version: Optional[int], +) -> None: + """Append each row of a published group to the dump file, if enabled. + + Args: + source: Publish site tag (``"legacy_commit"`` or ``"finalizer"``). + group_id: Prompt-group id the rows belong to. + sample_ids: Canonical per-row sample ids (``{group_id}_g{i}``). + train_batch: Column tensors as passed to ``pack_payload``. + weight_version: Weight version stamped on the rows' tags. + """ + dump_dir = os.environ.get(_DUMP_ENV_VAR) + if not dump_dir: + return + os.makedirs(dump_dir, exist_ok=True) + path = os.path.join(dump_dir, f"train_rows_{source}.jsonl") + lines = [] + for i, sample_id in enumerate(sample_ids): + record = { + "source": source, + "group_id": group_id, + "sample_id": sample_id, + "weight_version": weight_version, + **{name: _row_value(tensor, i) for name, tensor in train_batch.items()}, + } + lines.append(json.dumps(record)) + with _G_WRITE_LOCK, open(path, "a") as f: + f.write("\n".join(lines) + "\n") diff --git a/nemo_rl/models/generation/vllm/vllm_worker_async.py b/nemo_rl/models/generation/vllm/vllm_worker_async.py index a70b7201475..ed3cab46473 100644 --- a/nemo_rl/models/generation/vllm/vllm_worker_async.py +++ b/nemo_rl/models/generation/vllm/vllm_worker_async.py @@ -16,6 +16,7 @@ import copy import gc import logging +import os import threading import time import uuid @@ -1010,6 +1011,13 @@ def _setup_vllm_server(self) -> "tuple[threading.Thread, str, uvicorn.Server]": base_url = f"http://{node_ip}:{free_port}/v1" print(f"Starting server on {base_url}") + byte_dir = os.environ.get("NRL_HTTP_BYTES_DIR") + if byte_dir: + # Perf-measurement tooling only (see nemo_rl/utils/http_byte_counter.py). + from nemo_rl.utils.http_byte_counter import HttpByteCounterMiddleware + + app = HttpByteCounterMiddleware(app, "vllm_worker", byte_dir) # type: ignore[assignment] + config = uvicorn.Config( app, host="0.0.0.0", diff --git a/nemo_rl/utils/http_byte_counter.py b/nemo_rl/utils/http_byte_counter.py new file mode 100644 index 00000000000..7038d35b053 --- /dev/null +++ b/nemo_rl/utils/http_byte_counter.py @@ -0,0 +1,82 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""Env-gated per-route HTTP byte counter (``NRL_HTTP_BYTES_DIR``). + +Measurement tooling for the token-capture perf comparison: sums request-body +and response-body bytes per path on the vLLM worker's in-process HTTP server +and periodically flushes an aggregate JSON. Mirrors Gym's +``HttpByteCounterMiddleware`` (separate copy: worker venvs cannot assume +``nemo_gym`` is installed on the legacy path). Never installed unless the env +var is set. +""" + +import json +import os +from typing import Any, Awaitable, Callable + +Scope = dict[str, Any] +Message = dict[str, Any] +Receive = Callable[[], Awaitable[Message]] +Send = Callable[[Message], Awaitable[None]] + + +class HttpByteCounterMiddleware: + """Pure ASGI wrapper counting per-path request/response body bytes.""" + + FLUSH_EVERY = 25 + + def __init__(self, app: Any, server_name: str, out_dir: str) -> None: + self.app = app + self.out_path = os.path.join(out_dir, f"{server_name}_{os.getpid()}.json") + os.makedirs(out_dir, exist_ok=True) + self.counts: dict[str, list[int]] = {} + self._events = 0 + + def _flush(self) -> None: + with open(self.out_path, "w") as f: + json.dump( + { + path: { + "requests": c[0], + "req_bytes": c[1], + "resp_bytes": c[2], + } + for path, c in self.counts.items() + }, + f, + ) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http": + return await self.app(scope, receive, send) + entry = self.counts.setdefault(scope["path"], [0, 0, 0]) + entry[0] += 1 + + async def counting_receive() -> Message: + message = await receive() + if message["type"] == "http.request": + entry[1] += len(message.get("body", b"")) + return message + + async def counting_send(message: Message) -> None: + if message["type"] == "http.response.body": + entry[2] += len(message.get("body", b"")) + await send(message) + + try: + await self.app(scope, counting_receive, counting_send) + finally: + self._events += 1 + if self._events % self.FLUSH_EVERY == 0: + self._flush() diff --git a/pyrefly.toml b/pyrefly.toml index 668b9c939b4..9806035e376 100644 --- a/pyrefly.toml +++ b/pyrefly.toml @@ -133,6 +133,7 @@ project-includes = [ "nemo_rl/evals/answer_parsing.py", "nemo_rl/experience/__init__.py", "nemo_rl/experience/blackbox_finalizer.py", + "nemo_rl/experience/row_dump.py", "nemo_rl/experience/interfaces.py", "nemo_rl/experience/rollout_manager.py", "nemo_rl/experience/rollouts.py", @@ -181,6 +182,7 @@ project-includes = [ "nemo_rl/utils/__init__.py", "nemo_rl/utils/checkpoint.py", "nemo_rl/utils/config.py", + "nemo_rl/utils/http_byte_counter.py", "nemo_rl/utils/native_checkpoint.py", "nemo_rl/utils/nsys.py", "nemo_rl/utils/nvml.py", diff --git a/swe/SWE_RUN.md b/swe/SWE_RUN.md new file mode 100644 index 00000000000..ca0b52b9c9a --- /dev/null +++ b/swe/SWE_RUN.md @@ -0,0 +1,183 @@ +# SWE Run — Token-Capture vs Legacy Perf A/B at Scale + +Runbook for measuring the performance of the gate-authoritative token-capture +pipeline (`token_capture.enabled=true`, design: +`docs/design-docs/tq-gym-gate-authoritative.md`) against the legacy token-echo +path on a real workload: **async GRPO on SWE-bench** (Qwen3-30B-A3B thinking, +NeMo-Gym OpenHands agent, 16 nodes). This is the multi-turn run the 2-GPU S5 +experiments could not provide — SWE agents run up to 100–200 turns per +rollout, which is exactly where the legacy echo pays its per-turn token +re-transmission and where capture's `token_in_rate` and prefix serving are +finally exercised for real. + +Small-scale S5 results this run extends (implementation log, +`docs/design-docs/tq-gym-gate-authoritative-implementation-log.md` § S5): +−35.6 % HTTP bytes/trained token, −9 % step time, −16.8 % generation time on +a *single-turn* workload — the floor. The sync prototype measured −46.9 % +bytes/token multi-turn. + +--- + +## 1. The stack being launched + +``` +swe/launch_swe_ab.sh (this folder: picks the arm, derives the capture yaml) + └─ site wrapper e.g. .../nemo_rl-sc-test/test_assets/SWE/grpo_swe_tests.sh + (account, container, secrets, lustre paths — user-specific, gitignored) + └─ snapshot launcher /examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh + (env-agnostic: parallelism, async_rl/data_plane overrides, sbatch) + └─ ray.sub → SLURM (16 nodes: 8 train TP4/EP8/CP4/PP2 + 8 gen vLLM TP2, + seqlen 131072, SC_MODE=1 single-controller + TQ) +``` + +Jobs run from an immutable **code snapshot** +(`test_assets/SWE/sync_code.sh`). The snapshot rsyncs `3rdparty/` wholesale, +so the **local-only Gym fork commits ride along** — the open gitlink/CI +question does not block this experiment. + +## 2. The A/B design + +One independent variable. Everything else — snapshot, container, data, model, +parallelism, async_rl knobs, node count — identical between arms. + +| | Arm A: `legacy` | Arm B: `capture` | +|---|---|---| +| Config | site yaml as-is | site yaml + `token_capture.enabled: true` (derived by `make_capture_config.py`) | +| Token path | gate string-parses ids + `/tokenize` per call; ids/logprobs echoed through agent messages every turn; tokens ride the Ray return | gate custodies lineage; worker stages delta ids+logprobs to TQ once; markers + token-free receipts | +| Rows into training | `TQReplayBuffer.commit` tensorize | `BlackboxFinalizer` verify → publish | + +Both arms use the launcher's defaults, which sit inside the capture MVP +matrix: `batch_selection_strategy=staleness_window`, age 1, +`mixed_weight_version_policy=allow` (default), async vLLM engine, +non-colocated generation. `make_capture_config.py` also pins +`rollout_max_attempts_to_avoid_lp_nan: 1` — capture setup hard-errors +otherwise (NaN-retry would re-register create-only rollout ids); it is set on +**both** arms' derived configs so retry behavior is not a confound. + +### Run protocol (perf reading) + +1. **Flag-off smoke first** (`MAX_NUM_STEPS=3`): proves the branch + Gym pin + reproduce the legacy SWE run before anything is compared. The standing + dormant-by-default discipline. +2. **Measurement runs**: `MAX_NUM_STEPS=20`–`30` per arm (long enough that + medians beat setup noise; short enough to iterate). `--dependency=singleton` + is already in the launcher — submit both arms back-to-back under the same + job name family so they land on comparable allocations. +3. **Repeats**: 1 pair = directional; 3 pairs = quotable (the S5 assessment: + run-to-run variance on this stack is plausibly ±5–10 %). + +## 3. Launching + +### Prerequisites (once) + +- The branch state you want measured is **committed** (RL repo and Gym + submodule) — snapshots are cut from a checkout. +- A checkout of `yukih/sc-entrypoint` (with the `tq-gate-capture` submodule + state) on lustre to snapshot from, e.g. clone + check out, or reuse an + existing sc-test workspace updated to this branch. +- A personal site wrapper (copy + `test_assets/SWE/grpo_swe_tests.sh` and edit ACCOUNT / CONTAINER / + secrets-profile / cache / W&B paths for your user). +- Snapshot it: + +```bash +cd # repo root, branch checked out +bash test_assets/SWE/sync_code.sh sc-swe-capture +``` + +### Submitting the arms + +```bash +# from this repo's swe/ folder +SITE_WRAPPER=/lustre/.../your_grpo_swe_tests.sh \ + MAX_NUM_STEPS=3 ARM=legacy bash swe/launch_swe_ab.sh # flag-off smoke + +SITE_WRAPPER=... MAX_NUM_STEPS=25 ARM=legacy bash swe/launch_swe_ab.sh +SITE_WRAPPER=... MAX_NUM_STEPS=25 ARM=capture bash swe/launch_swe_ab.sh + +# optional: HTTP byte accounting (writes per-server JSON to lustre) +SITE_WRAPPER=... MAX_NUM_STEPS=25 ARM=capture BYTES=1 bash swe/launch_swe_ab.sh +``` + +`launch_swe_ab.sh` does four things: derives the arm's config +(`make_capture_config.py` for the capture arm), stamps +`EXP_SUFFIX=swe-ab--...` so W&B separates the arms, forces the venv +posture below, and `exec`s your site wrapper (all launcher knobs still pass +through the environment: `TP`, `PPS`, `OVER_SAMPLING`, `DRY_RUN=1`, …). + +### Environment posture (why the wrapper forces these) + +- **`NRL_FORCE_REBUILD_VENVS=true` on BOTH arms.** The baked container's + `/opt/ray_venvs` predate this branch's `uv.lock` (S1 regenerated it), and + the capture arm additionally needs the `VLLM_GYM` worker venv + (`--extra vllm --extra nemo_gym`) that no image bakes yet. Forcing rebuild + on both arms keeps setup cost out of the A/B. Pre-warm `LUSTRE_UV_CACHE` + once (see the launcher header) or the first node-local build is ~30 min — + the 180-min idle-GPU reaper exemption in the site wrapper covers it. +- **`GYM_VENV_DIR=/tmp/nemo_gym_venvs` (node-local rebuild) on BOTH arms.** + The baked `/opt/gym_venvs` were built against the old Gym pin; the fork + bumped dependency floors (e.g. aiohttp). The editable install means *code* + comes from the mounted fork either way, but stale *deps* would crash the + policy-model server on import. Rebaking the image + (`test_assets/SWE/prebuild_gym_venvs.sh`) removes this cost permanently. + +## 4. What to compare (the perf read) + +All of these land in W&B (both arms) — the capture-arm `gate/*` block comes +from the per-step SC gate-metrics logging added in S5. + +**Headline perf (medians over steps 5..N, skipping warm-up):** + +| Metric (W&B key) | Expectation | +|---|---| +| `timing/train/total_step_time` | capture ≤ legacy; S5 saw −9 % single-turn | +| `timing/train/exposed_generation` | the mechanism lives here (no `/tokenize` round-trip, ~40 % smaller per-call payloads, no echo growth); S5 saw −16.8 % | +| `timing/train/valid_tokens_per_sec_per_gpu` | inverse of the above | + +**Capture-arm health / mechanism metrics:** + +| Metric | What it tells you | +|---|---| +| `gate/token_in_rate` | THE number this run finally measures. High (→1.0 for continuations) = OpenHands echoes markers faithfully and exact-prefix serving works at depth. Low = fallbacks (see next row) — runs stay *correct* but pay full re-renders. | +| `gate/fallback_no_marker` / `fallback_fingerprint_miss` / `fallback_unknown_marker` | Which § 3.3 fallback is firing if token_in_rate is low. `fingerprint_miss` at scale ⇒ the OpenHands history pipeline rewrites messages (report back — this is marker-survival risk #1 for agent frameworks). | +| `gate/capture_failed`, `train/global_valid_seqs` | staging failures → placeholder rows. valid_seqs should equal GBS on both arms. | +| `finalize/*` (rollout metrics) | finalizer latency rides the dispatch task (MVP placement) — SWE's 131k-token multi-call rollouts make this worth watching; if it dominates dispatch, that argues for the H5 finalizer pool. | + +**Training equivalence (guards the perf claim):** overlay `train/reward` +curves and `train/gen_kl_error` between arms — same band = the perf delta is +not bought with training drift. (S5: identical rewards 10/10, same KL band.) + +**Optional byte accounting (`BYTES=1`):** env-gated ASGI counters +(`NG_HTTP_BYTES_DIR` on every Gym server — the SWE config runs +`num_workers: 1`, which the counter supports — and `NRL_HTTP_BYTES_DIR` on +the vLLM workers) write per-server, per-route JSON to +`/http_bytes/`. Aggregate with `swe/aggregate_perf.py + ` → total bytes, bytes per trained token, per-hop +table. Expect the multi-turn reduction to land between the S5 floor +(−35.6 %) and beyond the prototype's −46.9 % as turn count grows. + +## 5. Known risks at this scale (accepted, watched) + +- **Gate death = silent stall, not loud failure** (S5 chaos finding, fix + queued for H1): Gym's control-plane client retries a dead gate unboundedly, + so if the policy-model server dies mid-run the job hangs rather than + failing. Supervise; `squeue` + driver log tell you which. +- **Gate buffer growth is uncapped** (H5 adds caps): per-rollout delta + forests, ids only. At seqlen 131k × concurrency 768 the raw ids are modest + (~100s of MB), but Python-object overhead is real — watch the policy-model + server RSS. +- **Marker survival through OpenHands** is the biggest unknown — it uses the + same message carrier the legacy token echo uses (so it *should* survive + wherever legacy works today), but `token_in_rate` is the proof either way, + and a low rate is a correctness-preserving perf bug, not a training bug. +- The idle-GPU reaper exemption and `checkpoint_must_save_by` are already + handled by the site wrapper / launcher. + +## 6. Files in this folder + +| File | Purpose | +|---|---| +| `SWE_RUN.md` | this runbook | +| `launch_swe_ab.sh` | arm selector: derives config, names the run, forces venv posture, delegates to your site wrapper | +| `make_capture_config.py` | derives the arm configs from the site yaml (`token_capture.enabled` + NaN-retry pin) | +| `aggregate_perf.py` | offline aggregation: per-hop HTTP bytes, bytes/trained-token, timing medians, token_in_rate | diff --git a/swe/aggregate_perf.py b/swe/aggregate_perf.py new file mode 100644 index 00000000000..c5490a60ebd --- /dev/null +++ b/swe/aggregate_perf.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""Aggregate the instrumented legacy-vs-capture perf pair. + +Usage: python aggregate_perf.py + +Each run dir: http_bytes/*.json (per-server per-route byte counters), +metrics.json (TB dump), train_rows_*.jsonl (row dump for token counts). +""" + +import glob +import json +import os +import sys + + +def load_bytes(run_dir): + per_server = {} + for path in glob.glob(os.path.join(run_dir, "http_bytes", "*.json")): + name = os.path.basename(path).rsplit("_", 1)[0] + data = json.load(open(path)) + agg = per_server.setdefault(name, {}) + for route, c in data.items(): + e = agg.setdefault(route, {"requests": 0, "req_bytes": 0, "resp_bytes": 0}) + for k in e: + e[k] += c[k] + return per_server + + +def total_trained_tokens(run_dir): + total = 0 + for path in glob.glob(os.path.join(run_dir, "train_rows_*.jsonl")): + for line in open(path): + if line.strip(): + total += json.loads(line)["input_lengths"] + return total + + +def timing(run_dir): + d = json.load(open(os.path.join(run_dir, "metrics.json"))) + out = {} + for key in ( + "timing/train/total_step_time", + "timing/train/exposed_generation", + "timing/train/policy_training", + "timing/train/weight_sync", + "timing/train/valid_tokens_per_sec_per_gpu", + "train/gen_kl_error", + "train/reward", + "gate/token_in_rate", + "gate/token_in", + "gate/fallback_no_marker", + "gate/fallback_fingerprint_miss", + ): + s = d.get(key) + if isinstance(s, dict) and s: + vals = [v for _, v in sorted(s.items(), key=lambda kv: int(kv[0]))] + out[key] = vals + return out + + +def main(): + legacy_dir, capture_dir = sys.argv[1], sys.argv[2] + report = {} + for tag, run_dir in (("legacy", legacy_dir), ("capture", capture_dir)): + servers = load_bytes(run_dir) + toks = total_trained_tokens(run_dir) + grand = {"requests": 0, "req_bytes": 0, "resp_bytes": 0} + print(f"\n===== {tag} =====") + for name, routes in sorted(servers.items()): + s = {"requests": 0, "req_bytes": 0, "resp_bytes": 0} + for route, c in routes.items(): + for k in s: + s[k] += c[k] + for k in grand: + grand[k] += s[k] + print(f"{name:32s} req={s['requests']:6d} in={s['req_bytes']/1e6:8.2f} MB out={s['resp_bytes']/1e6:8.2f} MB") + for route, c in sorted(routes.items(), key=lambda kv: -(kv[1]["req_bytes"] + kv[1]["resp_bytes"]))[:4]: + print(f" {route:40s} n={c['requests']:5d} in={c['req_bytes']/1e6:7.2f} MB out={c['resp_bytes']/1e6:7.2f} MB") + total_bytes = grand["req_bytes"] + grand["resp_bytes"] + print(f"{'TOTAL':32s} req={grand['requests']:6d} bytes={total_bytes/1e6:.2f} MB trained_tokens={toks} bytes/token={total_bytes/max(toks,1):.1f}") + report[tag] = {"total_bytes": total_bytes, "tokens": toks, "timing": timing(run_dir)} + + lt, ct = report["legacy"], report["capture"] + print("\n===== comparison =====") + bt_l = lt["total_bytes"] / max(lt["tokens"], 1) + bt_c = ct["total_bytes"] / max(ct["tokens"], 1) + print(f"HTTP bytes/trained token: legacy {bt_l:.1f} -> capture {bt_c:.1f} ({(bt_c/bt_l-1)*100:+.1f}%)") + for key in ("timing/train/total_step_time", "timing/train/exposed_generation", "timing/train/valid_tokens_per_sec_per_gpu"): + lv, cv = lt["timing"].get(key), ct["timing"].get(key) + if lv and cv: + import statistics + ml, mc = statistics.median(lv), statistics.median(cv) + print(f"{key}: legacy median {ml:.3f} -> capture median {mc:.3f} ({(mc/ml-1)*100:+.1f}%)") + tir = ct["timing"].get("gate/token_in_rate") + if tir: + print(f"capture token_in_rate (cumulative, final): {tir[-1]:.3f}") + + +if __name__ == "__main__": + main() diff --git a/swe/launch_swe_ab.sh b/swe/launch_swe_ab.sh new file mode 100755 index 00000000000..56537d53785 --- /dev/null +++ b/swe/launch_swe_ab.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +# ============================================================================= +# SWE token-capture A/B arm launcher — see swe/SWE_RUN.md. +# +# Picks the arm, derives its config, names the run, forces the venv posture, +# then delegates to YOUR site wrapper (account/container/secrets live there). +# All launcher knobs (TP, PPS, MAX_NUM_STEPS, DRY_RUN=1, ...) pass through. +# +# Required: +# ARM=legacy|capture +# SITE_WRAPPER=/path/to/your grpo_swe_tests.sh-style wrapper +# Optional: +# BYTES=1 enable per-hop HTTP byte counters (JSON under the +# checkpoint dir; aggregate with swe/aggregate_perf.py) +# BASE_CONFIG site yaml to derive from (default: the wrapper's default, +# discovered via CONFIG_FILE after the wrapper sources it — +# set explicitly if your wrapper computes CONFIG_FILE late) +# ============================================================================= +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ARM="${ARM:?set ARM=legacy|capture}" +SITE_WRAPPER="${SITE_WRAPPER:?set SITE_WRAPPER=/path/to/your site wrapper}" +[[ "${ARM}" == "legacy" || "${ARM}" == "capture" ]] || { echo "ARM must be legacy|capture" >&2; exit 1; } + +# ---- Derive the arm's config from the site yaml ----------------------------- +# Default BASE_CONFIG: the yaml sitting next to the site wrapper (the +# grpo_swe_tests.sh convention). Override for other layouts. +BASE_CONFIG="${BASE_CONFIG:-$(dirname "${SITE_WRAPPER}")/grpo_qwen3_30b_async_swe.yaml}" +[ -f "${BASE_CONFIG}" ] || { echo "BASE_CONFIG not found: ${BASE_CONFIG}" >&2; exit 1; } +DERIVED_DIR="${DERIVED_DIR:-$(dirname "${BASE_CONFIG}")/derived_configs}" +mkdir -p "${DERIVED_DIR}" +export CONFIG_FILE="${DERIVED_DIR}/grpo_swe_ab_${ARM}.yaml" +python3 "${SCRIPT_DIR}/make_capture_config.py" "${BASE_CONFIG}" "${CONFIG_FILE}" "${ARM}" + +# ---- Run naming (W&B separates the arms) ------------------------------------ +export EXP_SUFFIX="${EXP_SUFFIX:-swe-ab-${ARM}-$(date +%m%d%H%M)}" + +# ---- Venv posture: identical on both arms (see SWE_RUN.md § 3) -------------- +# Baked /opt/ray_venvs predate this branch's lock; the capture arm needs the +# unbaked VLLM_GYM worker venv. Forcing rebuild on both arms keeps setup cost +# out of the A/B. +export NRL_FORCE_REBUILD_VENVS=true +# Baked /opt/gym_venvs deps predate the Gym fork's floors; node-local rebuild. +export GYM_VENV_DIR="${GYM_VENV_DIR:-/tmp/nemo_gym_venvs}" + +# ---- Optional per-hop HTTP byte accounting ---------------------------------- +if [ "${BYTES:-0}" = "1" ]; then + BYTES_DIR="${BYTES_DIR:-${CHECKPOINT_ROOT:-$(dirname "${SITE_WRAPPER}")/../..}/http_bytes/${EXP_SUFFIX}}" + mkdir -p "${BYTES_DIR}" + export NG_HTTP_BYTES_DIR="${BYTES_DIR}" + export NRL_HTTP_BYTES_DIR="${BYTES_DIR}" + echo "[launch_swe_ab] byte counters on -> ${BYTES_DIR}" +fi + +echo "[launch_swe_ab] arm=${ARM} config=${CONFIG_FILE} exp=${EXP_SUFFIX}" +exec bash "${SITE_WRAPPER}" "$@" diff --git a/swe/make_capture_config.py b/swe/make_capture_config.py new file mode 100644 index 00000000000..5880a736655 --- /dev/null +++ b/swe/make_capture_config.py @@ -0,0 +1,50 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +"""Derive the SWE A/B arm configs from a site yaml (see swe/SWE_RUN.md). + +Usage: + python swe/make_capture_config.py legacy|capture + +Both arms get `env.nemo_gym.rollout_max_attempts_to_avoid_lp_nan: 1` (the +capture arm hard-errors without it; pinning it on both keeps NaN-retry +behavior out of the A/B). The capture arm additionally gets +`token_capture.enabled: true` — the gate config injection into the Gym +policy-model server happens in code (`environments/nemo_gym.py:_spinup`), +so no other yaml change is needed. +""" + +import sys + +import yaml + + +def main() -> None: + src, dst, arm = sys.argv[1], sys.argv[2], sys.argv[3] + assert arm in ("legacy", "capture"), f"arm must be legacy|capture, got {arm}" + with open(src) as f: + config = yaml.safe_load(f) + + config.setdefault("env", {}).setdefault("nemo_gym", {})[ + "rollout_max_attempts_to_avoid_lp_nan" + ] = 1 + if arm == "capture": + config.setdefault("token_capture", {})["enabled"] = True + + with open(dst, "w") as f: + yaml.safe_dump(config, f, sort_keys=False) + print(f"[make_capture_config] arm={arm}: {src} -> {dst}") + + +if __name__ == "__main__": + main() diff --git a/tests/functional/L1_Functional_Tests_SingleController.sh b/tests/functional/L1_Functional_Tests_SingleController.sh index 2a6fad63eea..201ac4cf02a 100755 --- a/tests/functional/L1_Functional_Tests_SingleController.sh +++ b/tests/functional/L1_Functional_Tests_SingleController.sh @@ -36,6 +36,9 @@ run_test() { run_test fast uv run --no-sync bash ./tests/functional/grpo_dp_single_controller.sh run_test fast uv run --no-sync bash ./tests/functional/grpo_async_gym_single_controller.sh +# Token-capture (gate-authoritative) path: same SC+Gym smoke with the gate +# custodying token lineage and the finalizer publishing training rows. +run_test uv run --no-sync bash ./tests/functional/grpo_async_gym_single_controller.sh ++token_capture.enabled=true cd ${PROJECT_ROOT}/tests if compgen -G ".coverage*" > /dev/null; then From ef4ef4ba29b953ca4b28619540a5941db5507ebf Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 17:13:18 -0700 Subject: [PATCH 37/44] feat(sc): add examples/swe_bench async GRPO SWE launcher + recipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Env-agnostic SLURM launcher (ray.sub, 16 nodes: 8 train + 8 gen, SC_MODE=1 single-controller default) and Qwen3-30B-A3B-Thinking recipe, imported from the sc-test workspace (biguo) so the token-capture SWE A/B (swe/SWE_RUN.md) can snapshot from this branch. Site-specific values (account, container, secrets, data/model paths) come from a personal wrapper — the published yaml carries placeholder sandbox-image paths. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- examples/swe_bench/README.md | 85 +++ .../swe_bench/grpo_qwen3_30b_async_swe.yaml | 436 ++++++++++++++ .../swe_bench/run_grpo_qwen3_30b_async_swe.sh | 558 ++++++++++++++++++ 3 files changed, 1079 insertions(+) create mode 100644 examples/swe_bench/README.md create mode 100644 examples/swe_bench/grpo_qwen3_30b_async_swe.yaml create mode 100644 examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh diff --git a/examples/swe_bench/README.md b/examples/swe_bench/README.md new file mode 100644 index 00000000000..3f30f5f4520 --- /dev/null +++ b/examples/swe_bench/README.md @@ -0,0 +1,85 @@ +# Async GRPO on SWE-bench (Qwen3-30B-A3B) + +Launcher and recipe for agentic RL on SWE-bench via NeMo-Gym/OpenHands: +16 nodes by default (8 training + 8 generation, non-colocated), async GRPO +with staleness window 1. + +| File | Purpose | +|---|---| +| `run_grpo_qwen3_30b_async_swe.sh` | SLURM launcher (submits `ray.sub`) | +| `grpo_qwen3_30b_async_swe.yaml` | Recipe config | + +The launcher supports two entrypoints: + +- `SC_MODE=1` (default): `examples/run_grpo_single_controller.py` — + single-controller with the TransferQueue data plane. +- `SC_MODE=0`: `examples/nemo_gym/run_grpo_nemo_gym.py` — classic async GRPO + (async behavior comes from the yaml's `grpo.async_grpo` block). + +## Prerequisites + +1. A NeMo-RL checkout (or code snapshot) containing `ray.sub` at its root — + the launcher submits from the root it lives under. +2. An enroot container image of a recent NeMo-RL nightly. +3. The SWE train dataset (`.jsonl`). +4. The SWE sandbox images (apptainer/singularity `.sif` files for the + swe-bench / sweap instances). **Edit the `container_formatter` lists in the + yaml** to point at your local copies (they ship as `/path/to/...` + placeholders). +5. A HF checkpoint to train from. + +## Quick start + +Run from the repo root: + +```bash +ACCOUNT= \ +CONTAINER=/path/to/nemo-rl-nightly.sqsh \ +MODEL_PATH=/path/to/hf_checkpoint \ +TRAIN_DATA_PATH=/path/to/swe_train.jsonl \ +EXTRA_MOUNTS=/path/to/shared_fs:/path/to/shared_fs \ +bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh +``` + +`EXTRA_MOUNTS` must make the model / data / `.sif` locations visible inside +the container (the default mounts only cover the repo tree and the gym +source). Add `DRY_RUN=1` to print the sbatch command and config without +submitting. + +Secrets (`WANDB_API_KEY`, `HUGGINGFACE_TOKEN`, ...) are read from the calling +environment and never stored in this directory. The recommended pattern is a +small personal wrapper script that exports your site-specific paths, cluster +account, and secrets, then calls this launcher. + +## Common variations + +```bash +# Classic (non-single-controller) entrypoint +SC_MODE=0 bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh + +# Different training tensor parallelism +TP=2 bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh + +# streaming-2 dispatch semantics (over-generation + out-of-order consumption; +# default is streaming-1: strict repro of classic async_grpo age-1 dispatch) +OVER_SAMPLING=true FORCE_IN_ORDER=false \ +bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh + +# Finer intra-step dispatch: start training once 2 prompt groups are ready +# instead of waiting for the full batch (SC only; PPS=8 by default) +MIN_PROMPT_GROUPS=2 bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh + +# Smaller / shorter run +NUM_NODES=8 NUM_GEN_NODES=4 TIME=2:0:0 MAX_NUM_STEPS=5 \ +bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh +``` + +The full knob list (parallelism, batch sizes, staleness, agent turn limits, +caches, ...) is documented in the launcher's header comment. + +## Monitoring + +The submit banner prints the experiment name, W&B target, and log location. +The driver log lands at `/logs/slurm/-logs/ray-driver.log`; +training progress appears there as `train step ...` / `step_metrics=...` +lines and in W&B under `train/reward` and `timing/train/*`. diff --git a/examples/swe_bench/grpo_qwen3_30b_async_swe.yaml b/examples/swe_bench/grpo_qwen3_30b_async_swe.yaml new file mode 100644 index 00000000000..aa774156245 --- /dev/null +++ b/examples/swe_bench/grpo_qwen3_30b_async_swe.yaml @@ -0,0 +1,436 @@ +# ============================================================================ +# Async GRPO SWE RL Training: Qwen3-30B-A3B-Thinking-2507 +# +# Model: Qwen3-30B-A3B-Thinking-2507 (MoE, 30B total / 3B active, thinking) +# Train data: R2E-Gym (r2e-gym subset, 4518 samples) +# Eval data: SWE-bench Verified +# Mode: Async GRPO with non-colocated generation +# Entry: examples/nemo_gym/run_grpo_nemo_gym.py +# Env: swe_agents (OpenHands agent, singularity sandbox) +# +# Based on: bihu/nemo-rl-qwen-swe/grpo_qwen3_30b_thinking_swe.yaml +# Gym: main branch (nemo-rl-async-swe repo) +# ============================================================================ + +checkpointing: + enabled: true + checkpoint_dir: "results/grpo-qwen3-30b-thinking-swe-rl" + metric_name: "train:total_reward/mean" + higher_is_better: true + keep_top_k: 100 + save_period: 5 + checkpoint_must_save_by: "00:03:35:00" + model_save_format: "safetensors" + save_consolidated: false + save_optimizer: true + +grpo: + num_prompts_per_step: 16 + num_generations_per_prompt: 16 + num_val_generations_per_prompt: 1 + max_rollout_turns: 1 + max_num_epochs: 100 + max_num_steps: 1000000 + normalize_rewards: true + use_leave_one_out_baseline: true + advantage_clip_low: -100 + advantage_clip_high: 100 + val_period: 10 + val_at_start: false + val_at_end: false + overlong_filtering: true + max_val_samples: null + val_batch_size: 256 + seed: 42 + invalid_tool_call_strategy: "" + + use_dynamic_sampling: false + dynamic_sampling_max_gen_batches: 10 + batch_multiplier: 1 + + penalize_invalid_tool_call: true + invalid_tool_call_advantage: -5.0 + penalize_malformed_thinking: true + malformed_thinking_advantage: -5.0 + + reward_shaping: + enabled: false + overlong_buffer_length: 128 + overlong_buffer_penalty: 1 + max_response_length: ${policy.max_total_sequence_length} + stop_properly_penalty_coef: null + reward_scaling: + enabled: false + source_min: 0.0 + source_max: 1.0 + target_min: 0.0 + target_max: 1.0 + + async_grpo: + enabled: true + max_trajectory_age_steps: 1 + in_flight_weight_updates: true + recompute_kv_cache_after_weight_updates: false + + seq_logprob_error_threshold: 2 + +loss_fn: + reference_policy_kl_penalty: 0.0 + reference_policy_kl_type: "k3" + kl_input_clamp_value: null + kl_output_clamp_value: null + ratio_clip_min: 0.2 + ratio_clip_max: 0.28 + ratio_clip_c: null + use_on_policy_kl_approximation: true + use_importance_sampling_correction: true + truncated_importance_sampling_ratio: 5.0 + truncated_importance_sampling_ratio_min: null + truncated_importance_sampling_type: tis + sequence_level_importance_ratios: false + token_level_loss: true + force_on_policy_ratio: true + use_kl_in_reward: false + +policy: + model_name: "Qwen/Qwen3-30B-A3B-Thinking-2507" + tokenizer: + name: ${policy.model_name} + chat_template_kwargs: + enable_thinking: true + hf_config_overrides: {} + train_global_batch_size: 256 + train_micro_batch_size: 1 + generation_batch_size: 64 + logprob_batch_size: 1 + max_total_sequence_length: 131072 + precision: "bfloat16" + logprob_chunk_size: 2048 + offload_optimizer_for_logprob: false + + dtensor_cfg: + _v2: true + enabled: false + cpu_offload: False + sequence_parallel: false + activation_checkpointing: false + tensor_parallel_size: 1 + context_parallel_size: 1 + custom_parallel_plan: null + + megatron_cfg: + enabled: true + gradient_accumulation_fusion: false + empty_unused_memory_level: 1 + activation_checkpointing: true + tensor_model_parallel_size: 2 + expert_tensor_parallel_size: 1 + expert_model_parallel_size: 8 + pipeline_model_parallel_size: 2 + num_layers_in_first_pipeline_stage: null + num_layers_in_last_pipeline_stage: null + context_parallel_size: 4 + pipeline_dtype: ${policy.precision} + sequence_parallel: true + freeze_moe_router: true + moe_router_dtype: "fp32" + moe_router_load_balancing_type: "none" + moe_router_bias_update_rate: 1.0e-3 + moe_permute_fusion: true + moe_enable_deepep: false + moe_token_dispatcher_type: "alltoall" + moe_aux_loss_coeff: 0.0 + moe_router_enable_expert_bias: true + moe_shared_expert_overlap: false + apply_rope_fusion: True + bias_activation_fusion: False + defer_fp32_logits: True + moe_per_layer_logging: True + + optimizer: + optimizer: "adam" + lr: 1.0e-6 + min_lr: 1.0e-6 + weight_decay: 0.0 + bf16: true + fp16: false + params_dtype: "float32" + adam_beta1: 0.9 + adam_beta2: 0.999 + adam_eps: 1e-8 + sgd_momentum: 0.9 + use_distributed_optimizer: true + use_precision_aware_optimizer: true + clip_grad: ${policy.max_grad_norm} + optimizer_cpu_offload: false + optimizer_offload_fraction: 0.0 + + scheduler: + start_weight_decay: ${policy.megatron_cfg.optimizer.weight_decay} + end_weight_decay: ${policy.megatron_cfg.optimizer.weight_decay} + weight_decay_incr_style: "constant" + lr_decay_style: "constant" + lr_decay_iters: 1000000 + lr_warmup_iters: 0 + lr_warmup_init: 0 + + distributed_data_parallel_config: + grad_reduce_in_fp32: false + overlap_grad_reduce: false + overlap_param_gather: false + use_custom_fsdp: false + data_parallel_sharding_strategy: "optim_grads_params" + + mtp_loss_scaling_factor: 0.0 + mtp_use_repeated_layer: false + mtp_num_layers: 0 + mtp_detach_heads: false + + fp8_cfg: + enabled: false + fp8: "e4m3" + fp8_recipe: "blockwise" + fp8_param: false + + env_vars: null + + dynamic_batching: + enabled: False + train_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.train_micro_batch_size}} + logprob_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.logprob_batch_size}} + sequence_length_round: 64 + + sequence_packing: + enabled: True + train_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.train_micro_batch_size}} + logprob_mb_tokens: ${mul:${policy.max_total_sequence_length}, ${policy.logprob_batch_size}} + algorithm: "modified_first_fit_decreasing" + sequence_length_round: 64 + + make_sequence_length_divisible_by: 8 + max_grad_norm: 1.0 + + optimizer: null + scheduler: null + + generation: + port_range_low: 11001 + port_range_high: 15000 + backend: "vllm" + max_new_tokens: ${policy.max_total_sequence_length} + temperature: 1.0 + top_p: 1.0 + top_k: null + stop_token_ids: null + stop_strings: null + vllm_cfg: + enable_prefix_caching: true + async_engine: true + precision: ${policy.precision} + kv_cache_dtype: "auto" + tensor_parallel_size: 2 + pipeline_parallel_size: 1 + expert_parallel_size: 1 + gpu_memory_utilization: 0.8 + max_model_len: ${policy.max_total_sequence_length} + enforce_eager: False + enforce_monotonicity: false + use_deep_gemm: False + num_last_layers_in_bf16: 0 + num_first_layers_in_bf16: 0 + enable_vllm_metrics_logger: true + vllm_metrics_logger_interval: 0.5 + expose_http_server: true + skip_tokenizer_init: false + enable_thinking: true + http_server_serving_chat_kwargs: + enable_auto_tools: true + tool_parser: hermes + reasoning_parser: deepseek_r1 + chat_template: | + {%- if tools %} + {{- '<|im_start|>system\n' }} + {%- if messages[0].role == 'system' %} + {{- messages[0].content + '\n\n' }} + {%- endif %} + {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }} + {%- for tool in tools %} + {{- "\n" }} + {{- tool | tojson }} + {%- endfor %} + {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }} + {%- else %} + {%- if messages[0].role == 'system' %} + {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }} + {%- endif %} + {%- endif %} + {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %} + {%- for message in messages[::-1] %} + {%- set index = (messages|length - 1) - loop.index0 %} + {%- if ns.multi_step_tool and message.role == "user" and message.content is string and not(message.content.startswith('') and message.content.endswith('')) %} + {%- set ns.multi_step_tool = false %} + {%- set ns.last_query_index = index %} + {%- endif %} + {%- endfor %} + {%- for message in messages %} + {%- if message.content is string %} + {%- set content = message.content %} + {%- else %} + {%- set content = '' %} + {%- endif %} + {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} + {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }} + {%- elif message.role == "assistant" %} + {%- set reasoning_content = '' %} + {%- if message.reasoning_content is string %} + {%- set reasoning_content = message.reasoning_content %} + {%- else %} + {%- if '' in content %} + {%- set reasoning_content = content.split('')[0].rstrip('\n').split('')[-1].lstrip('\n') %} + {%- set content = content.split('')[-1].lstrip('\n') %} + {%- endif %} + {%- endif %} + {%- if reasoning_content %} + {{- '<|im_start|>' + message.role + '\n\n' + reasoning_content.strip('\n') + '\n\n\n' + content.lstrip('\n') }} + {%- else %} + {{- '<|im_start|>' + message.role + '\n' + content }} + {%- endif %} + {%- if message.tool_calls %} + {%- for tool_call in message.tool_calls %} + {%- if (loop.first and content) or (not loop.first) %} + {{- '\n' }} + {%- endif %} + {%- if tool_call.function %} + {%- set tool_call = tool_call.function %} + {%- endif %} + {{- '\n{"name": "' }} + {{- tool_call.name }} + {{- '", "arguments": ' }} + {%- if tool_call.arguments is string %} + {{- tool_call.arguments }} + {%- else %} + {{- tool_call.arguments | tojson }} + {%- endif %} + {{- '}\n' }} + {%- endfor %} + {%- endif %} + {{- '<|im_end|>\n' }} + {%- elif message.role == "tool" %} + {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %} + {{- '<|im_start|>user' }} + {%- endif %} + {{- '\n\n' }} + {{- content }} + {{- '\n' }} + {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} + {{- '<|im_end|>\n' }} + {%- endif %} + {%- endif %} + {%- endfor %} + {%- if add_generation_prompt %} + {{- '<|im_start|>assistant\n\n' }} + {%- endif %} + default_chat_template_kwargs: + enable_thinking: true + truncate_history_thinking: false + + vllm_kwargs: + mamba_ssm_cache_dtype: "float32" + # The default flashinfer MoE backend (trtllm_bf16_moe) uses a fused/quantized + # expert weight layout that does NOT match the megatron weight-refit broadcast, + # producing garbage generations (and can hang broadcast_weights_for_collective). + # triton uses the standard expert layout the refit broadcast expects. + # Mirrors ruit's grpo_qwen3_30b_async_swe_hsg.yaml on the swe2-scale-gen branch. + moe_backend: triton + compilation_config: + cudagraph_capture_sizes: [1,2,4,8,16,32,64] + + colocated: + enabled: false + resources: + gpus_per_node: 8 + num_nodes: 4 + +data: + max_input_seq_length: null + shuffle: false + num_workers: 1 + use_multiple_dataloader: false + train: + # Site-specific; the launcher always overrides this via ++data.train.data_path. + data_path: "/path/to/swe_train_dataset.jsonl" + validation: + # Site-specific; the launcher always overrides this via ++data.validation.data_path. + data_path: "/path/to/swe_val_dataset.jsonl" + default: + dataset_name: NemoGymDataset + env_name: "nemo_gym" + prompt_file: null + system_prompt_file: null + processor: "nemo_gym_data_processor" + +env: + should_use_nemo_gym: true + should_log_nemo_gym_responses: false + nemo_gym: + skip_venv_if_present: true + port_range_low: 15001 + port_range_high: 20000 + config_paths: + - responses_api_models/vllm_model/configs/vllm_model_for_training.yaml + - responses_api_agents/swe_agents/configs/swebench_openhands_training.yaml + swe_agents_train: + responses_api_agents: + swe_agents: + agent_max_turns: 100 + concurrency: 768 + swebench_agent_timeout: 3600 + run_with_mixed_prompts: true + dataset_path: ${data.train.data_path} + # Site-specific: apptainer/singularity .sif sandbox images for the SWE + # datasets, tried in order per instance. Point these at your local + # copies of the swe-bench / sweap image sets. + container_formatter: + - "/path/to/swe-bench-images/swebench_sweb.eval.x86_64.{instance_id}.sif" + - "/path/to/sweap-images/sweap.{instance_id}.sif" + - "/path/to/swe-bench-images/namanjain12_{instance_id}.sif" + - "/path/to/sweap-images/sweap.{instance_id}.sif" + - "/path/to/swe-bench-images/swebench_sweb.eval.x86_64{instance_id}.sif" + swe_agents_val: + responses_api_agents: + swe_agents: + agent_max_turns: 200 + concurrency: 768 + swebench_agent_timeout: 3600 + dataset_path: ${data.validation.data_path} + # Site-specific: see the note on swe_agents_train.container_formatter. + container_formatter: + - "/path/to/swe-bench-images/swebench_sweb.eval.x86_64.{instance_id}.sif" + - "/path/to/sweap-images/sweap.{instance_id}.sif" + - "/path/to/swe-bench-images/namanjain12_{instance_id}.sif" + - "/path/to/sweap-images/sweap.{instance_id}.sif" + - "/path/to/swe-bench-images/swebench_sweb.eval.x86_64{instance_id}.sif" + use_absolute_ip: true + +logger: + log_dir: "logs" + num_val_samples_to_print: 0 + wandb_enabled: true + tensorboard_enabled: false + mlflow_enabled: false + monitor_gpus: true + swanlab_enabled: false + wandb: + project: "ruit-nemo-rl" + name: "qwen3-30b-thinking-swe-rl" + tensorboard: {} + mlflow: + experiment_name: "qwen3-30b-thinking-swe-rl" + run_name: "qwen3-30b-thinking-swe-rl" + gpu_monitoring: + collection_interval: 10 + flush_interval: 10 + +cluster: + gpus_per_node: 8 + num_nodes: 16 diff --git a/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh b/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh new file mode 100644 index 00000000000..bfde16e6f3e --- /dev/null +++ b/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh @@ -0,0 +1,558 @@ +#!/bin/bash +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. +# ============================================================================= +# Async GRPO on SWE-bench (NeMo-Gym / OpenHands) — Qwen3-30B-A3B, SLURM launcher. +# +# Submits a 16-node (8 train + 8 generation, non-colocated) async GRPO run via +# ray.sub. Supports both entrypoints: +# SC_MODE=1 (default) examples/run_grpo_single_controller.py +# (single-controller + TransferQueue data plane) +# SC_MODE=0 examples/nemo_gym/run_grpo_nemo_gym.py +# (classic async GRPO; async comes from the yaml's +# grpo.async_grpo block) +# +# This file is environment-agnostic: no secrets and no user-specific paths. +# Site-specific values come from the environment (see REQUIRED below) — wrap +# this script with your own launcher that exports them (see +# test_assets/SWE/grpo_swe_tests.sh for an example wrapper). +# +# --------------------------------------------------------------------------- +# REQUIRED environment: +# ACCOUNT SLURM account +# CONTAINER enroot .sqsh/.squashfs image (a recent NeMo-RL nightly; +# must postdate the TransferQueue pyproject dependency) +# MODEL_PATH HF checkpoint dir to train from +# TRAIN_DATA_PATH SWE train jsonl +# +# Common optional environment (see defaults inline for the full list): +# PARTITION (batch), NUM_NODES (16), NUM_GEN_NODES (8), TIME (4:0:0) +# VAL_DATA_PATH (=TRAIN_DATA_PATH), CONFIG_FILE (yaml next to this script) +# TP/EP/CP/PP/VLLM_TP, SEQLEN, PPS/GPP/GBS, LR, MAX_NUM_STEPS +# SC_MODE (1), MIN_PROMPT_GROUPS (=PPS) +# OVER_SAMPLING (false), FORCE_IN_ORDER (true) +# streaming-1 (default): OVER_SAMPLING=false FORCE_IN_ORDER=true +# — no over-generation, each step consumes the groups dispatched +# for it; 1:1 repro of the classic async_grpo (age=1) dispatch. +# streaming-2: OVER_SAMPLING=true FORCE_IN_ORDER=false +# — generation keeps producing, steps consume any groups within +# the staleness window; stale groups get evicted (wasted). +# PERSISTENT_CACHE compile/uv cache root on shared fs (~/.cache/... default) +# GYM_VENV_DIR /tmp/nemo_gym_venvs default; /opt/gym_venvs if your image +# has the gym server venvs baked in +# MOUNTS / EXTRA_MOUNTS container mounts (make model/data paths visible!) +# WANDB_API_KEY + WANDB_PROJ + EXP_SUFFIX logging & naming +# HUGGINGFACE_TOKEN / GITHUB_TOKEN / GITLAB_TOKEN passed through if set +# REAPER_COMMENT SLURM --comment payload (cluster-specific; empty default) +# DRY_RUN=1 print everything, submit nothing +# +# Usage (from a repo/snapshot root that contains ray.sub): +# ACCOUNT=... CONTAINER=... MODEL_PATH=... TRAIN_DATA_PATH=... \ +# bash examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh +# ============================================================================= + +set -e + +# --------------------------------------------------------------------------- +# Locate the tree to submit from: this script lives at examples/swe_bench/ +# inside the repo (or a code snapshot); ray.sub must exist at its root. +# --------------------------------------------------------------------------- +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RUN_DIR="${RUN_DIR:-$(cd "${SCRIPT_DIR}/../.." && pwd)}" +if [ ! -f "${RUN_DIR}/ray.sub" ]; then + echo "Error: ${RUN_DIR}/ray.sub not found — RUN_DIR must be a NeMo-RL checkout/snapshot root." >&2 + exit 1 +fi +RUN_COMMIT="unknown" +if git -C "${RUN_DIR}" rev-parse --short HEAD >/dev/null 2>&1; then + RUN_COMMIT="$(git -C "${RUN_DIR}" rev-parse --short HEAD)" +elif [ -f "${RUN_DIR}/commit.txt" ]; then + RUN_COMMIT="$(cut -c1-7 "${RUN_DIR}/commit.txt")" +fi + +# --------------------------------------------------------------------------- +# Required site-specific inputs — fail fast with a clear message. +# --------------------------------------------------------------------------- +missing="" +[ -n "${ACCOUNT:-}" ] || missing+=" ACCOUNT" +[ -n "${CONTAINER:-}" ] || missing+=" CONTAINER" +[ -n "${MODEL_PATH:-}" ] || missing+=" MODEL_PATH" +[ -n "${TRAIN_DATA_PATH:-}" ] || missing+=" TRAIN_DATA_PATH" +if [ -n "${missing}" ]; then + echo "Error: missing required environment variables:${missing}" >&2 + echo "See the header of this script for the full contract." >&2 + exit 1 +fi + +# --------------------------------------------------------------------------- +# Cluster / submission (site-specific, all overridable) +# --------------------------------------------------------------------------- +PARTITION="${PARTITION:-batch}" +GPUS_PER_NODE="${GPUS_PER_NODE:-8}" +CPUS_PER_WORKER="${CPUS_PER_WORKER:-114}" +# SLURM --comment payload (e.g. idle-GPU-reaper exemptions on some clusters). +REAPER_COMMENT="${REAPER_COMMENT:-}" + +# --------------------------------------------------------------------------- +# Scale / walltime +# --------------------------------------------------------------------------- +NUM_NODES="${NUM_NODES:-16}" # total allocation +NUM_GEN_NODES="${NUM_GEN_NODES:-8}" # carved out of NUM_NODES for generation +TIME="${TIME:-4:0:0}" +MAX_NUM_STEPS="${MAX_NUM_STEPS:-}" # empty => use the yaml's value + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- +CONFIG_FILE="${CONFIG_FILE:-${SCRIPT_DIR}/grpo_qwen3_30b_async_swe.yaml}" +VAL_DATA_PATH="${VAL_DATA_PATH:-${TRAIN_DATA_PATH}}" + +# ============================ Parallelism ============================ +TP="${TP:-4}"; EP="${EP:-8}"; CP="${CP:-4}"; PP="${PP:-2}"; VLLM_TP="${VLLM_TP:-2}" +MIN_PAD=1 +[ "${CP}" -gt 1 ] && MIN_PAD=$((MIN_PAD * CP * 2)) +[ "${TP}" -gt 1 ] && MIN_PAD=$((MIN_PAD * TP)) +MAKE_SEQ_DIVISIBLE_BY="${MIN_PAD}" +SEQUENCE_PACKING=True + +# ===================== Sequence length ===================== +SEQLEN="${SEQLEN:-131072}" + +# ===== Single-controller async-RL knobs (SC_MODE=1: data_plane + async_rl) ===== +# Maps the classic async_grpo (age=1) 1:1 to async_rl. +MAX_TRAJECTORY_AGE_STEPS="${MAX_TRAJECTORY_AGE_STEPS:-1}" # -> async_rl.max_weight_staleness_versions +BATCH_SELECTION_STRATEGY=staleness_window +# Dispatch semantics ("streaming" modes). Defaults = strict 1:1 repro of the +# classic async_grpo age-1 behavior (streaming-1): no over-generation, rollouts +# consumed strictly by their dispatch-target step. streaming-2 = the code +# defaults (over_sampling=true force_in_order=false): generation keeps +# producing (stale groups get evicted/wasted) and steps consume any groups +# inside the staleness window, out of order. +OVER_SAMPLING="${OVER_SAMPLING:-false}" +FORCE_IN_ORDER="${FORCE_IN_ORDER:-true}" +FORCE_ON_POLICY_RATIO=True +SEQ_LOGPROB_ERROR_THRESHOLD=null +COLOCATED_ENABLED=False +VLLM_GPU_UTIL=0.8 +OVERLAP_GRAD_REDUCE=False +ADVANTAGE_CLIP_LOW=-100 +ADVANTAGE_CLIP_HIGH=100 +TIS_THRESHOLD=5 + +# ========================= GRPO / sampling ========================= +PPS="${PPS:-8}"; GPP="${GPP:-8}"; GBS="${GBS:-64}" +# Intra-step dispatch granularity (SC only): the sampler releases work to the +# trainer once this many complete prompt groups are ready (gradient +# accumulation; the optimizer still steps only after PPS groups). Not passed in +# => same as PPS = fully synchronous within the step; smaller values overlap +# trainer compute with the generation tail. +MIN_PROMPT_GROUPS="${MIN_PROMPT_GROUPS:-${PPS}}" +NORMALIZE_REWARDS=True +OVERLONG_FILTERING=True +VAL_PERIOD="${VAL_PERIOD:-1000}" + +# ========================== Loss function ========================== +KL=0 +CLIP_MIN=0.2 +CLIP_MAX=0.28 +USE_ON_POLICY_KL_APPROXIMATION=True +IMPORTANCE_SAMPLING_CORRECTION=True +SEQ_LEVEL_IS=False +TOKEN_LEVEL_LOSS=True + +# ============================ Optimizer ============================ +LR="${LR:-1e-06}" + +# =============================== MoE =============================== +MOE_FREEZE_ROUTER=True +MOE_PERMUTE_FUSION=True +MOE_ENABLE_DEEPEP=False +MOE_TOKEN_DISPATCHER_TYPE="alltoall" +MOE_AUX_LOSS_COEFF=0 +MOE_ROUTER_LOAD_BALANCING_TYPE="none" +MOE_ROUTER_BIAS_UPDATE_RATE="1e-3" + +# ======================= Generation / vLLM ======================= +TEMPERATURE=1.0 + +# =================== Checkpointing & validation =================== +SAVE_PERIOD="${SAVE_PERIOD:-5}" +KEEP_TOP_K="${KEEP_TOP_K:-2}" +MUST_SAVE_BY="${MUST_SAVE_BY:-00:03:35:00}" # graceful save+exit before TIME + +# ============================ SWE agent ============================ +AGENT_MAX_TURNS="${AGENT_MAX_TURNS:-200}" +AGENT_TIMEOUT="${AGENT_TIMEOUT:-1800}" + +# ============================== Logging ============================== +WANDB_PROJ="${WANDB_PROJ:-nemo-rl-swe-bench}" +LOG_GYM_RESPONSES=true + +# ========================= Experiment naming ========================= +SYNC_MODE="async-age${MAX_TRAJECTORY_AGE_STEPS}" +EXP_SUFFIX="${EXP_SUFFIX:-swe-sc@${RUN_COMMIT}-${SYNC_MODE}-pps${PPS}-gpp${GPP}-gbs${GBS}-lr${LR}-tp${TP}}" +WANDB_NAME="${EXP_SUFFIX}" +EXP_NAME="${EXP_SUFFIX}" +CHECKPOINT_ROOT="${CHECKPOINT_ROOT:-${RUN_DIR}/results}" +CHECKPOINT_DIR="${CHECKPOINT_DIR:-${CHECKPOINT_ROOT}/${EXP_SUFFIX}}" +BASE_LOG_DIR="${BASE_LOG_DIR:-${RUN_DIR}/logs/slurm}" + +# ========================= Runtime env ========================= +# Secrets are passed through from the caller's environment; never set here. +export HUGGINGFACE_TOKEN="${HUGGINGFACE_TOKEN:-${HF_TOKEN:-}}" +export GITHUB_TOKEN="${GITHUB_TOKEN:-}" +export GITLAB_TOKEN="${GITLAB_TOKEN:-}" +export WANDB_API_KEY="${WANDB_API_KEY:-}" +export HF_HOME="${HF_HOME:-${HOME}/.cache/huggingface}" +export HF_DATASETS_CACHE="${HF_DATASETS_CACHE:-${HF_HOME}/datasets}" +# Node-local uv cache (ephemeral). Each node builds its own venv independently — +# a shared-filesystem uv cache corrupts under concurrent multi-node builds. +# Pre-warm LUSTRE_UV_CACHE once with a single process to skip long compiles. +export UV_CACHE_DIR=/tmp/uv_cache +export UV_LOCK_TIMEOUT=3600 +export RAY_DEDUP_LOGS=1 +export SSL_CERT_FILE="${SSL_CERT_FILE:-/etc/ssl/certs/ca-certificates.crt}" +export REQUESTS_CA_BUNDLE="${REQUESTS_CA_BUNDLE:-/etc/ssl/certs/ca-certificates.crt}" +export CURL_CA_BUNDLE="${CURL_CA_BUNDLE:-/etc/ssl/certs/ca-certificates.crt}" +export OMP_NUM_THREADS="${OMP_NUM_THREADS:-16}" + +# ===================== Shared-fs compile caches ===================== +# Runtime caches stay node-local (/tmp); the shared-fs copies are only seeded +# from (read) at startup and written back by a periodic sidecar, so repeat runs +# skip the ~20min triton MoE JIT. +PERSISTENT_CACHE="${PERSISTENT_CACHE:-${HOME}/.cache/nemo_rl_swe_bench}" +export LUSTRE_VLLM_CACHE="${PERSISTENT_CACHE}/vllm_compile_cache" +export LUSTRE_INDUCTOR_CACHE="${PERSISTENT_CACHE}/inductor_cache" +export LUSTRE_TRITON_CACHE="${PERSISTENT_CACHE}/triton_cache" +export LUSTRE_UV_CACHE="${PERSISTENT_CACHE}/uv_cache" +export NRL_VLLM_LOCAL_CACHE_DIR="/tmp/nemo_rl_vllm_cache" +export NRL_VLLM_CACHE_SEED_DIR="/tmp/nemo_rl_vllm_cache_warm" +export INDUCTOR_CACHE_DIR="/tmp/nemo_rl_inductor_cache" +export TRITON_CACHE_DIR="/tmp/nemo_rl_triton_cache" +export CACHE_SYNC_FREQUENCY="${CACHE_SYNC_FREQUENCY:-120}" +mkdir -p "${LUSTRE_VLLM_CACHE}" "${LUSTRE_INDUCTOR_CACHE}" "${LUSTRE_TRITON_CACHE}" "${LUSTRE_UV_CACHE}" + +# ===================== NeMo-Gym server venvs ===================== +# Default: node-local build (safe everywhere). If your container has the gym +# server venvs baked in (vllm_model + swe_agents), export GYM_VENV_DIR=/opt/gym_venvs. +# Do NOT point this at a shared filesystem: the editable nemo-gym build hangs on +# uv's flock there, and interrupted builds leave empty venv shells that +# skip-if-present then reuses -> the gym policy_model server crashes on import. +GYM_VENV_DIR="${GYM_VENV_DIR:-/tmp/nemo_gym_venvs}" +case "${GYM_VENV_DIR}" in /opt/*|/tmp/*) ;; *) mkdir -p "${GYM_VENV_DIR}" ;; esac + +# ===== SETUP_COMMAND: install apptainer + seed caches + uv sync ===== +# Runs on all nodes before Ray starts (consumed by ray.sub). +read -r -d '' SETUP_COMMAND </dev/null || true +RET=1 +RETRIES=3 +for attempt in \$(seq 1 \$RETRIES); do + if command -v apptainer >/dev/null 2>&1 || command -v singularity >/dev/null 2>&1; then + echo "[SETUP] singularity/apptainer already available" + RET=0 + break + fi + cd /tmp && \ + wget --no-check-certificate -q https://github.com/apptainer/apptainer/releases/download/v1.3.1/apptainer_1.3.1_amd64.deb && \ + apt install -y ./apptainer_1.3.1_amd64.deb && \ + ln -sf /usr/bin/apptainer /usr/bin/singularity + if command -v apptainer >/dev/null 2>&1; then + echo "[SETUP] apptainer installed successfully" + RET=0 + break + fi + echo "[SETUP] apptainer install attempt \$attempt failed, retrying..." + sleep 10 +done +if [ \$RET -ne 0 ]; then + echo "[SETUP] WARNING: apptainer installation failed after \$RETRIES attempts" +fi + +echo "[CACHE SEED] Clearing stale /tmp caches and seeding from shared fs..." +rm -rf /tmp/nemo_rl_vllm_cache /tmp/nemo_rl_vllm_cache_* +rm -rf "${INDUCTOR_CACHE_DIR}" "${TRITON_CACHE_DIR}" +mkdir -p "${INDUCTOR_CACHE_DIR}" "${TRITON_CACHE_DIR}" + +find "${LUSTRE_INDUCTOR_CACHE}" -maxdepth 1 -name '.tmp_*' -mmin +30 -exec rm -rf {} + 2>/dev/null || true +find "${LUSTRE_TRITON_CACHE}" -maxdepth 1 -name '.tmp_*' -mmin +30 -exec rm -rf {} + 2>/dev/null || true + +_seed_cache() { + local lustre="\$1" local_dir="\$2" name="\$3" + if [ -d "\$lustre" ] && [ "\$(ls -A "\$lustre" 2>/dev/null)" ]; then + rsync -a --exclude '.tmp_*' "\$lustre/" "\$local_dir/" 2>/dev/null \ + && echo "[CACHE SEED] \$name: seeded from shared fs" \ + || echo "[CACHE SEED] \$name: seed failed (non-fatal)" + else + echo "[CACHE SEED] \$name: no warm cache on shared fs yet" + fi +} + +_seed_cache "${LUSTRE_INDUCTOR_CACHE}" "${INDUCTOR_CACHE_DIR}" "Inductor" +_seed_cache "${LUSTRE_TRITON_CACHE}" "${TRITON_CACHE_DIR}" "Triton" +# uv cache: read-only rsync of single-process-prebuilt wheels into node-local +# /tmp so the uv sync below is a cache hit, not a ~28min build. +# (NOTE: no backticks/'\$(...)' in this heredoc body -- they would be command- +# substituted on the LOGIN node when SETUP_COMMAND is read.) +mkdir -p "${UV_CACHE_DIR}" +_seed_cache "${LUSTRE_UV_CACHE}" "${UV_CACHE_DIR}" "uv (prebuilt wheels)" +echo "[CACHE SEED] Done." + +# ===== Compile-cache WRITE-BACK sidecar ===== +# The seed above only READS shared fs -> /tmp. This sidecar periodically rsyncs +# /tmp -> shared fs (and on TERM/INT) so compiled kernels persist across runs; +# --ignore-existing makes concurrent per-node writes first-writer-wins. +_sync_cache_one() { + local src="\$1" dst="\$2" name="\$3" + mkdir -p "\$dst" + if [ -d "\$src" ] && [ "\$(ls -A "\$src" 2>/dev/null)" ]; then + rsync -a --ignore-existing --exclude '.tmp_*' --exclude 'tmp*' "\$src/" "\$dst/" 2>/dev/null \ + && echo "[CACHE SYNC] \$name: /tmp -> shared fs" \ + || echo "[CACHE SYNC] \$name: sync failed (non-fatal)" + fi +} +_sync_compile_caches_to_lustre() { + _sync_cache_one "${INDUCTOR_CACHE_DIR}" "${LUSTRE_INDUCTOR_CACHE}" "Inductor" + _sync_cache_one "${TRITON_CACHE_DIR}" "${LUSTRE_TRITON_CACHE}" "Triton" +} +_start_cache_sync_sidecar() { + local pidfile="/tmp/nemo_rl_compile_cache_sync.pid" + if [ -f "\$pidfile" ] && kill -0 "\$(cat "\$pidfile" 2>/dev/null)" 2>/dev/null; then + echo "[CACHE SYNC] sidecar already running (pid=\$(cat "\$pidfile" 2>/dev/null))" + return + fi + ( + set +e + trap '_sync_compile_caches_to_lustre; exit 0' TERM INT + echo "[CACHE SYNC] sidecar started, frequency=${CACHE_SYNC_FREQUENCY}s" + while true; do + sleep "${CACHE_SYNC_FREQUENCY}" + _sync_compile_caches_to_lustre + done + ) > /tmp/nemo_rl_compile_cache_sync.log 2>&1 & + echo "\$!" > "\$pidfile" + echo "[CACHE SYNC] sidecar pid=\$!" +} +if [ "${CACHE_SYNC_FREQUENCY}" -gt 0 ] 2>/dev/null; then + _start_cache_sync_sidecar +else + echo "[CACHE SYNC] disabled (CACHE_SYNC_FREQUENCY=${CACHE_SYNC_FREQUENCY})" +fi + +UV_HTTP_TIMEOUT=3600 \ + uv sync --frozen --extra mcore +SETUPEOF +export SETUP_COMMAND + +# Optional extra grpo overrides (only emitted when set, so empty == use yaml). +EXTRA_GRPO="" +[ -n "${MAX_NUM_STEPS}" ] && EXTRA_GRPO="grpo.max_num_steps=${MAX_NUM_STEPS}" + +# ===== Entrypoint switch: SC (single-controller) vs classic async GRPO ===== +# SC_MODE=1 (default): examples/run_grpo_single_controller.py + data_plane/async_rl overrides. +# SC_MODE=0: examples/nemo_gym/run_grpo_nemo_gym.py — the gym-dedicated classic +# entry; async comes from the yaml's native grpo.async_grpo block. +# (The generic examples/run_grpo.py is NOT wired for nemo-gym: it +# discards the gym actor instead of binding task_to_env["nemo_gym"], +# and its configure_generation_config eos injection trips the gym +# rollout stop-criteria assert.) +SC_MODE="${SC_MODE:-1}" +if [ "${SC_MODE}" = "1" ]; then + ENTRYPOINT="./examples/run_grpo_single_controller.py" + SC_OVERRIDES="++data_plane.enabled=true \ + ++data_plane.impl=transfer_queue \ + ++data_plane.backend=simple \ + ++data_plane.storage_capacity=1000000 \ + ++data_plane.num_storage_units=2 \ + ++data_plane.claim_meta_poll_interval_s=0.5 \ + ++data_plane.global_segment_size=549755813888 \ + ++data_plane.local_buffer_size=68719476736 \ + ++async_rl.max_weight_staleness_versions=${MAX_TRAJECTORY_AGE_STEPS} \ + ++async_rl.min_prompt_groups_per_batch=${MIN_PROMPT_GROUPS} \ + ++async_rl.max_inflight_prompts=${PPS} \ + ++async_rl.max_buffered_rollouts=$((PPS * (MAX_TRAJECTORY_AGE_STEPS + 1))) \ + ++async_rl.batch_selection_strategy=${BATCH_SELECTION_STRATEGY} \ + ++async_rl.over_sampling=${OVER_SAMPLING} \ + ++async_rl.force_in_order=${FORCE_IN_ORDER}" +else + ENTRYPOINT="./examples/nemo_gym/run_grpo_nemo_gym.py" + SC_OVERRIDES="" +fi + +# ===== Training command ===== +export COMMAND="NRL_VLLM_USE_V1=1 \ + NRL_WG_USE_RAY_REF=1 \ + WANDB_API_KEY=${WANDB_API_KEY} \ + HUGGINGFACE_TOKEN=${HUGGINGFACE_TOKEN} \ + GITHUB_TOKEN=${GITHUB_TOKEN} \ + GITLAB_TOKEN=${GITLAB_TOKEN} \ + HF_HOME=${HF_HOME} \ + HF_DATASETS_CACHE=${HF_DATASETS_CACHE} \ + UV_CACHE_DIR=${UV_CACHE_DIR} \ + VLLM_ATTENTION_BACKEND=FLASH_ATTN \ + VLLM_CACHE_ROOT=${LUSTRE_VLLM_CACHE} \ + DG_JIT_CACHE_DIR=${LUSTRE_VLLM_CACHE}/deep_gemm \ + VLLM_DEEP_GEMM_WARMUP=skip \ + NRL_FORCE_REBUILD_VENVS=${NRL_FORCE_REBUILD_VENVS:-false} \ + NRL_SKIP_TQ_RUNTIME_ENV_PATCH=${NRL_SKIP_TQ_RUNTIME_ENV_PATCH:-1} \ + NRL_IGNORE_VERSION_MISMATCH=1 \ + RAY_ENABLE_UV_RUN_RUNTIME_ENV=0 \ + UV_HTTP_TIMEOUT=3600 \ + UV_LOCK_TIMEOUT=900 \ + TORCH_CUDA_ARCH_LIST='9.0 10.0' \ + NEMO_GYM_SKIP_VENV_IF_PRESENT=1 \ + NEMO_GYM_VENV_DIR=${GYM_VENV_DIR} \ + uv run --frozen --extra mcore ${ENTRYPOINT} \ + --config=${CONFIG_FILE} \ + cluster.num_nodes=${NUM_NODES} \ + cluster.gpus_per_node=${GPUS_PER_NODE} \ + ++data.train.data_path=${TRAIN_DATA_PATH} \ + ++data.validation.data_path=${VAL_DATA_PATH} \ + grpo.num_prompts_per_step=${PPS} \ + grpo.num_generations_per_prompt=${GPP} \ + grpo.val_at_start=False \ + grpo.normalize_rewards=${NORMALIZE_REWARDS} \ + grpo.overlong_filtering=${OVERLONG_FILTERING} \ + grpo.val_period=${VAL_PERIOD} \ + grpo.seq_logprob_error_threshold=${SEQ_LOGPROB_ERROR_THRESHOLD} \ + ${EXTRA_GRPO} \ + ${SC_OVERRIDES} \ + ++policy.draft.enabled=false \ + ++policy.draft.model_name=null \ + ++policy.draft.loss_weight=0.1 \ + ++policy.draft.num_layers=null \ + ++policy.draft.aux_layer_indices=null \ + env.should_log_nemo_gym_responses=${LOG_GYM_RESPONSES} \ + policy.generation.colocated.enabled=${COLOCATED_ENABLED} \ + policy.model_name=${MODEL_PATH} \ + policy.max_total_sequence_length=${SEQLEN} \ + policy.dynamic_batching.enabled=False \ + policy.train_global_batch_size=${GBS} \ + policy.make_sequence_length_divisible_by=${MAKE_SEQ_DIVISIBLE_BY} \ + policy.offload_optimizer_for_logprob=true \ + policy.sequence_packing.enabled=${SEQUENCE_PACKING} \ + policy.megatron_cfg.tensor_model_parallel_size=${TP} \ + policy.megatron_cfg.expert_model_parallel_size=${EP} \ + policy.megatron_cfg.context_parallel_size=${CP} \ + policy.megatron_cfg.pipeline_model_parallel_size=${PP} \ + policy.megatron_cfg.sequence_parallel=True \ + policy.megatron_cfg.bias_activation_fusion=False \ + ++policy.megatron_cfg.use_fused_weighted_squared_relu=false \ + policy.megatron_cfg.distributed_data_parallel_config.overlap_grad_reduce=${OVERLAP_GRAD_REDUCE} \ + policy.megatron_cfg.moe_permute_fusion=${MOE_PERMUTE_FUSION} \ + policy.megatron_cfg.moe_enable_deepep=${MOE_ENABLE_DEEPEP} \ + policy.megatron_cfg.moe_token_dispatcher_type=${MOE_TOKEN_DISPATCHER_TYPE} \ + policy.megatron_cfg.moe_aux_loss_coeff=${MOE_AUX_LOSS_COEFF} \ + policy.megatron_cfg.moe_router_load_balancing_type=${MOE_ROUTER_LOAD_BALANCING_TYPE} \ + policy.megatron_cfg.moe_router_bias_update_rate=${MOE_ROUTER_BIAS_UPDATE_RATE} \ + policy.megatron_cfg.freeze_moe_router=${MOE_FREEZE_ROUTER} \ + policy.megatron_cfg.optimizer.lr=${LR} \ + policy.megatron_cfg.optimizer.min_lr=${LR} \ + policy.megatron_cfg.optimizer.weight_decay=0 \ + policy.megatron_cfg.empty_unused_memory_level=2 \ + policy.megatron_cfg.activation_checkpointing=True \ + policy.generation.temperature=${TEMPERATURE} \ + policy.generation.vllm_cfg.tensor_parallel_size=${VLLM_TP} \ + policy.generation.vllm_cfg.gpu_memory_utilization=${VLLM_GPU_UTIL} \ + policy.generation.vllm_cfg.skip_tokenizer_init=False \ + loss_fn.reference_policy_kl_penalty=${KL} \ + loss_fn.ratio_clip_min=${CLIP_MIN} \ + loss_fn.ratio_clip_max=${CLIP_MAX} \ + loss_fn.use_on_policy_kl_approximation=${USE_ON_POLICY_KL_APPROXIMATION} \ + loss_fn.use_importance_sampling_correction=${IMPORTANCE_SAMPLING_CORRECTION} \ + loss_fn.sequence_level_importance_ratios=${SEQ_LEVEL_IS} \ + loss_fn.token_level_loss=${TOKEN_LEVEL_LOSS} \ + loss_fn.force_on_policy_ratio=${FORCE_ON_POLICY_RATIO} \ + checkpointing.checkpoint_dir=${CHECKPOINT_DIR} \ + checkpointing.save_period=${SAVE_PERIOD} \ + checkpointing.keep_top_k=${KEEP_TOP_K} \ + ++checkpointing.metric_name=train:total_reward/mean \ + ++checkpointing.checkpoint_must_save_by=${MUST_SAVE_BY} \ + logger.wandb_enabled=True \ + logger.wandb.name=${WANDB_NAME} \ + logger.wandb.project=${WANDB_PROJ}" + +# Async non-colocated: generation cluster + clipping + agent turn/timeout knobs. +export COMMAND="${COMMAND} \ + policy.generation.colocated.resources.num_nodes=${NUM_GEN_NODES} \ + policy.generation.colocated.resources.gpus_per_node=${GPUS_PER_NODE} \ + grpo.advantage_clip_low=${ADVANTAGE_CLIP_LOW} \ + grpo.advantage_clip_high=${ADVANTAGE_CLIP_HIGH} \ + loss_fn.truncated_importance_sampling_ratio=${TIS_THRESHOLD} \ + env.nemo_gym.swe_agents_train.responses_api_agents.swe_agents.agent_max_turns=${AGENT_MAX_TURNS} \ + env.nemo_gym.swe_agents_train.responses_api_agents.swe_agents.swebench_agent_timeout=${AGENT_TIMEOUT} \ + env.nemo_gym.swe_agents_val.responses_api_agents.swe_agents.agent_max_turns=${AGENT_MAX_TURNS} \ + env.nemo_gym.swe_agents_val.responses_api_agents.swe_agents.swebench_agent_timeout=${AGENT_TIMEOUT}" + +# --------------------------------------------------------------------------- +# Mounts: the run tree at its own path (so ./examples/... resolves) and the +# gym source over the container's bundled copy. Export MOUNTS to replace, or +# EXTRA_MOUNTS to append (e.g. the filesystem holding MODEL_PATH/data). +# --------------------------------------------------------------------------- +GYM_CODE="${RUN_DIR}/3rdparty/Gym-workspace/Gym" +MOUNTS="${MOUNTS:-${RUN_DIR}:${RUN_DIR},${GYM_CODE}:/opt/nemo-rl/3rdparty/Gym-workspace/Gym}" +[ -n "${EXTRA_MOUNTS:-}" ] && MOUNTS="${MOUNTS},${EXTRA_MOUNTS}" + +mkdir -p "${CHECKPOINT_DIR}" "${BASE_LOG_DIR}" + +# ray.sub reads these from the environment. +export CONTAINER MOUNTS COMMAND SETUP_COMMAND GPUS_PER_NODE CPUS_PER_WORKER BASE_LOG_DIR +[ -n "${UV_CACHE_DIR_OVERRIDE:-}" ] && export UV_CACHE_DIR_OVERRIDE + +sbatch_args=( + --nodes="${NUM_NODES}" + --account="${ACCOUNT}" + --job-name="${EXP_NAME}" + --partition="${PARTITION}" + --time="${TIME}" + --gres=gpu:"${GPUS_PER_NODE}" + --exclusive + --dependency=singleton + --output="${BASE_LOG_DIR}/slurm-%j.out" +) +[ -n "${REAPER_COMMENT}" ] && sbatch_args+=(--comment="${REAPER_COMMENT}") +# shellcheck disable=SC2206 +[ -n "${SBATCH_EXTRA_ARGS:-}" ] && sbatch_args+=(${SBATCH_EXTRA_ARGS}) + +echo "==========================================" +echo "SWE async GRPO | Experiment: ${EXP_SUFFIX}" +echo "Entrypoint: ${ENTRYPOINT} (SC_MODE=${SC_MODE})" +echo "Run tree: ${RUN_DIR} @ ${RUN_COMMIT}" +echo "Account: ${ACCOUNT} / ${PARTITION}" +echo "Nodes: ${NUM_NODES} total (generation carves out ${NUM_GEN_NODES}) Time: ${TIME}" +echo "Container: ${CONTAINER}" +echo "Parallelism: TP=${TP}, EP=${EP}, CP=${CP}, PP=${PP}, vLLM_TP=${VLLM_TP}, pad=${MAKE_SEQ_DIVISIBLE_BY}" +echo "Training: PPS=${PPS}, GPP=${GPP}, GBS=${GBS}, LR=${LR}, seqlen=${SEQLEN}, max_steps=${MAX_NUM_STEPS:-}, min_prompt_groups=${MIN_PROMPT_GROUPS}" +echo "Streaming: over_sampling=${OVER_SAMPLING}, force_in_order=${FORCE_IN_ORDER}, age=${MAX_TRAJECTORY_AGE_STEPS}" +echo "Model: ${MODEL_PATH}" +echo "Checkpoint: ${CHECKPOINT_DIR}" +echo "WandB: ${WANDB_PROJ}/${WANDB_NAME}" +echo "==========================================" + +if [ "${DRY_RUN:-0}" = "1" ]; then + echo "[DRY_RUN] sbatch ${sbatch_args[*]} ${RUN_DIR}/ray.sub" + echo "[DRY_RUN] COMMAND (first 400 chars): ${COMMAND:0:400}..." + exit 0 +fi + +cd "${RUN_DIR}" +out=$(sbatch "${sbatch_args[@]}" "${RUN_DIR}/ray.sub") +echo "${out}" +job_id=$(echo "${out}" | grep -oE '[0-9]+' | head -1) +if [ -n "${job_id}" ]; then + echo "Job ID: ${job_id}" + echo "Monitor: squeue -j ${job_id}" + echo "Driver log: ${BASE_LOG_DIR}/${job_id}-logs/ray-driver.log" +fi From e710556508050ad52a89304bf3981d1213b4a58e Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 17:32:39 -0700 Subject: [PATCH 38/44] fix(sc): forward NG_HTTP_BYTES_DIR/NRL_HTTP_BYTES_DIR into the SWE job env The launcher predates the S5 byte counters; without forwarding, BYTES=1 in swe/launch_swe_ab.sh silently produced no per-hop accounting inside the sbatch job. Empty defaults keep the counters dormant. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh b/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh index bfde16e6f3e..182274a3c5a 100644 --- a/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh +++ b/examples/swe_bench/run_grpo_qwen3_30b_async_swe.sh @@ -406,6 +406,8 @@ export COMMAND="NRL_VLLM_USE_V1=1 \ DG_JIT_CACHE_DIR=${LUSTRE_VLLM_CACHE}/deep_gemm \ VLLM_DEEP_GEMM_WARMUP=skip \ NRL_FORCE_REBUILD_VENVS=${NRL_FORCE_REBUILD_VENVS:-false} \ + NG_HTTP_BYTES_DIR=${NG_HTTP_BYTES_DIR:-} \ + NRL_HTTP_BYTES_DIR=${NRL_HTTP_BYTES_DIR:-} \ NRL_SKIP_TQ_RUNTIME_ENV_PATCH=${NRL_SKIP_TQ_RUNTIME_ENV_PATCH:-1} \ NRL_IGNORE_VERSION_MISMATCH=1 \ RAY_ENABLE_UV_RUN_RUNTIME_ENV=0 \ From 26b845e69cc9a7671b378f93eeaca33479c1ecb3 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Tue, 28 Jul 2026 17:39:59 -0700 Subject: [PATCH 39/44] docs(sc): add pinned launch record for the SWE token-capture A/B Concrete experiment plan (exact commits/snapshot/compute shape/gates/ pre-flight checklist) for the run swe/SWE_RUN.md describes generically. Status: ready, not submitted. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- swe/EXPERIMENT_LAUNCH.md | 129 +++++++++++++++++++++++++++++++++++++++ swe/SWE_RUN.md | 1 + 2 files changed, 130 insertions(+) create mode 100644 swe/EXPERIMENT_LAUNCH.md diff --git a/swe/EXPERIMENT_LAUNCH.md b/swe/EXPERIMENT_LAUNCH.md new file mode 100644 index 00000000000..f9f3e9801f4 --- /dev/null +++ b/swe/EXPERIMENT_LAUNCH.md @@ -0,0 +1,129 @@ +# Experiment Launch Plan — SWE Token-Capture A/B (2026-07-28) + +Concrete launch record for the run described generically in `SWE_RUN.md`. +Everything here is pinned to what will actually execute; update this file if +any pin changes before submission. **Status: READY — not yet submitted.** + +## 1. Hypothesis and expected outcome + +The gate-authoritative token-capture pipeline +(`docs/design-docs/tq-gym-gate-authoritative.md`) reduces HTTP bytes per +trained token and wall-clock step time vs the legacy token-echo path on a +real multi-turn agentic workload, at equal training quality. + +| Expectation | Basis | +|---|---| +| Bytes/token reduction ≥ 35.6 % (the single-turn floor), toward/beyond −46.9 % (sync-prototype multi-turn) | S5 instrumented A/B; legacy pays per-turn history re-echo (~quadratic in turns), capture stays O(generated tokens) | +| `exposed_generation` and `total_step_time` at or below legacy | S5 saw −16.8 % / −9.0 % single-turn; expect relative timing win to compress on a 30B MoE (GPU decode dominates) while the bytes win grows | +| `gate/token_in_rate` → 1.0 for continuation calls | First real measurement — OpenHands marker survival is the biggest unknown (risk #1); a low rate is a correctness-preserving perf bug, not a training bug | +| Reward / KL curves in the same band on both arms | S5: identical rewards 10/10, same KL band | + +## 2. Exact pins + +| What | Value | +|---|---| +| RL repo | branch `yukih/sc-entrypoint` @ `e71055650` (local-only; no remote has it) | +| Gym fork (submodule) | branch `tq-gate-capture` @ `e3b3eac6` (= upstream #2124 head `32b555f04` + S1–S3 capture commits + S5 byte-counter middleware; local-only) | +| Code snapshot | `code_snapshots/sc-swe-capture` @ `e710556` (immutable run tree; both arms run from it) | +| Container | `nemo-rl:sc-swe-baked.sqsh` (biguo; nightly-062526 + baked venvs — **stale vs branch lock**, hence forced venv rebuild below) | +| Model | Qwen3-30B-A3B-Thinking-2507, from SWE1 `step_230_hf` checkpoint (bihu, run dc3m70us lineage) | +| Train data | R2E-Gym subset jsonl (sdevare), 4,518 samples | +| Site config | `test_assets/SWE/grpo_qwen3_30b_async_swe.yaml` (real sandbox-image paths; snapshot copy is authoritative at run time) | +| Derived arm configs | `test_assets/SWE/derived_configs/grpo_swe_ab_{legacy,capture}.yaml` — regenerated at each submit by `make_capture_config.py` | + +Verified diff between derived arm configs: **only** `token_capture.enabled: +true` on the capture arm; `rollout_max_attempts_to_avoid_lp_nan: 1` pinned on +**both** arms (capture hard-errors without it; pinning both removes the +NaN-retry confound). + +## 3. Compute shape (per job; one job per arm) + +- 16 nodes × 8 GPUs (128 GPUs), SLURM `batch` partition, account + `coreai_dlalgo_genai`, 4 h wall time, `--exclusive`, + `--dependency=singleton` (arms queue back-to-back on comparable + allocations), idle-GPU-reaper exemption (180 min) in the job comment. +- 8 training nodes: Megatron-Core, TP=4 EP=8 CP=4 PP=2, pad 32. +- 8 generation nodes: async vLLM, TP=2, non-colocated. +- Single-controller entrypoint (`SC_MODE=1`, + `examples/run_grpo_single_controller.py`) + TransferQueue data plane. +- Sequence budget 131,072; GBS=64 (8 prompts/step × 8 generations/prompt); + LR 1e-6; staleness `age=1`, `force_in_order=true`, `over_sampling=false`. +- Agent: NeMo-Gym OpenHands, per-instance Singularity sandboxes (`.sif` + under igitman/sdevare lustre trees), up to ~100–200 turns/rollout. + +## 4. Environment posture (identical on both arms) + +- `NRL_FORCE_REBUILD_VENVS=true` — container venvs predate the branch's + `uv.lock`; capture arm additionally needs the unbaked `VLLM_GYM` worker + venv. First node-local build may take ~30 min (reaper exemption covers it). +- `GYM_VENV_DIR=/tmp/nemo_gym_venvs` — baked `/opt/gym_venvs` deps predate + the Gym fork's floors (aiohttp bump). +- `BYTES=1` (capture-arm measurement run): `NG_HTTP_BYTES_DIR` + + `NRL_HTTP_BYTES_DIR` → per-server JSON under `http_bytes//`; + forwarding into the job env added in `e71055650`. +- Secrets: `profiles/env.sh` (mode 600) sourced by the site wrapper; wrapper + fails loudly if `WANDB_API_KEY`/`HF_TOKEN` are unset. + +## 5. Run sequence and gates + +All submissions via (from repo root): + +```bash +SITE_WRAPPER=$PWD/test_assets/SWE/grpo_swe_tests.sh MAX_NUM_STEPS= ARM= [BYTES=1] bash swe/launch_swe_ab.sh +``` + +| # | Run | Purpose | Gate to proceed | +|---|---|---|---| +| 1 | `ARM=legacy MAX_NUM_STEPS=3` | Flag-off smoke: branch + Gym pin reproduce the known-good legacy SWE run | Job completes 3 steps; reward/KL sane; no venv/import failures | +| 2 | `ARM=legacy MAX_NUM_STEPS=25` | Measurement baseline | Completes ≥ 20 steps cleanly | +| 3 | `ARM=capture MAX_NUM_STEPS=25 BYTES=1` | Measurement + mechanism + byte accounting | — | +| 4 | (optional) repeat pair ×2 | Variance bars; S5 assessment puts run-to-run variance at ±5–10 % | 1 pair = directional, 3 pairs = quotable | + +W&B: project `pthombre-swe-capture-ab`, runs named +`swe-ab--`. Checkpoints: `/results//`. + +## 6. Analysis plan + +- Medians over steps 5..N (skip warm-up): `timing/train/total_step_time`, + `timing/train/exposed_generation`, `timing/train/valid_tokens_per_sec_per_gpu`. +- Mechanism: `gate/token_in_rate` (the headline first-time measurement), + `gate/fallback_{no_marker,fingerprint_miss,unknown_marker}` — sustained + `fingerprint_miss` ⇒ OpenHands rewrites history (marker-survival risk #1; + report back to the design doc §11). +- Health: `gate/capture_failed`, `train/global_valid_seqs` == GBS both arms; + `finalize/*` latency (if it dominates dispatch → argues for H5 finalizer pool). +- Equivalence: overlay `train/reward` + `train/gen_kl_error` across arms. +- Bytes: `python swe/aggregate_perf.py ` + → total bytes, bytes/trained-token, per-hop table. +- Results recorded in + `docs/design-docs/tq-gym-gate-authoritative-implementation-log.md` (post-MVP + perf report per design § 10). + +## 7. Known risks (accepted, watched) + +- **Gate death = silent stall** (S5 chaos finding; H1 fix queued): control + plane retries a dead gate unboundedly → job hangs, doesn't fail. + Supervise via `squeue` + driver log in + `code_snapshots/sc-swe-capture/logs/slurm/`. +- **Gate buffer growth uncapped** (H5): ids-only delta forests; at 131k × + in-flight concurrency raw ids are ~100s MB but Python overhead is real — + watch policy-model server RSS. +- **OpenHands marker survival unknown** — measured, not assumed + (`token_in_rate`); low rate degrades perf, never correctness. +- **Secrets in job env**: the launcher embeds `WANDB_API_KEY`/HF token in + the sbatch command (visible in SLURM logs; pre-existing behavior). + Rotate tokens if logs are shared. +- Snapshot is immutable but the **derived configs are re-generated per + submit** — do not edit the site yaml between arms of a pair. + +## 8. Pre-flight checklist (all verified 2026-07-28) + +- [x] S1–S5 + launcher committed (RL `e71055650`, Gym `e3b3eac6`) +- [x] Snapshot `sc-swe-capture` @ `e710556`: S5 files, `examples/swe_bench/` + launcher, site yaml, Gym gate + byte middleware present +- [x] Dry-run both arms end-to-end (`DRY_RUN=1`): correct account, snapshot + paths, singleton, reaper comment; derived-config diff = capture flag only +- [x] Container / model / data / sandbox images readable by pthombre +- [x] SLURM account `coreai_dlalgo_genai` valid for user (nemotron_sw_post is not) +- [x] Secrets profile in place; wrapper verified with tokens stripped from env +- [ ] SUBMIT (awaiting explicit go) diff --git a/swe/SWE_RUN.md b/swe/SWE_RUN.md index ca0b52b9c9a..8e626fe8dec 100644 --- a/swe/SWE_RUN.md +++ b/swe/SWE_RUN.md @@ -178,6 +178,7 @@ table. Expect the multi-turn reduction to land between the S5 floor | File | Purpose | |---|---| | `SWE_RUN.md` | this runbook | +| `EXPERIMENT_LAUNCH.md` | pinned launch record for the 2026-07-28 A/B (exact commits, snapshot, gates, checklist) | | `launch_swe_ab.sh` | arm selector: derives config, names the run, forces venv posture, delegates to your site wrapper | | `make_capture_config.py` | derives the arm configs from the site yaml (`token_capture.enabled` + NaN-retry pin) | | `aggregate_perf.py` | offline aggregation: per-hop HTTP bytes, bytes/trained-token, timing medians, token_in_rate | From 3249559d611960624ea0efb858fd415a57991b0f Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Wed, 29 Jul 2026 00:08:37 -0700 Subject: [PATCH 40/44] fix(sc): use image-baked /opt/gym_venvs in the SWE A/B launcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A node-local GYM_VENV_DIR=/tmp rebuild only materializes on the NemoGym actor's node while Gym spawns servers cluster-wide — job 14542017 failed with missing venv pythons on every other node. The baked venvs are dep-compatible with the fork (swe_agents/vllm_model requirements unchanged vs the old pin) and editable installs carry the fork's code. Also record the uv-cache pre-warm requirement and the reaper's de facto 60-min idle kill in the runbook. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- swe/SWE_RUN.md | 21 +++++++++++++++------ swe/launch_swe_ab.sh | 9 +++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/swe/SWE_RUN.md b/swe/SWE_RUN.md index 8e626fe8dec..335eff4e6db 100644 --- a/swe/SWE_RUN.md +++ b/swe/SWE_RUN.md @@ -114,12 +114,21 @@ through the environment: `TP`, `PPS`, `OVER_SAMPLING`, `DRY_RUN=1`, …). on both arms keeps setup cost out of the A/B. Pre-warm `LUSTRE_UV_CACHE` once (see the launcher header) or the first node-local build is ~30 min — the 180-min idle-GPU reaper exemption in the site wrapper covers it. -- **`GYM_VENV_DIR=/tmp/nemo_gym_venvs` (node-local rebuild) on BOTH arms.** - The baked `/opt/gym_venvs` were built against the old Gym pin; the fork - bumped dependency floors (e.g. aiohttp). The editable install means *code* - comes from the mounted fork either way, but stale *deps* would crash the - policy-model server on import. Rebaking the image - (`test_assets/SWE/prebuild_gym_venvs.sh`) removes this cost permanently. +- **`GYM_VENV_DIR=/opt/gym_venvs` (image-baked) on BOTH arms.** A node-local + `/tmp` rebuild does NOT work multi-node: the venv build runs only on the + NemoGym actor's node while Gym spawns servers cluster-wide (job 14542017 + failed on exactly this). The baked venvs are dependency-compatible with the + fork (verified: `swe_agents`/`vllm_model` requirements unchanged vs the old + pin; only the core aiohttp CVE floor moved, irrelevant at runtime), and the + editable install serves the fork's *code* on every node. If a future fork + commit does change server deps, rebake via + `test_assets/SWE/prebuild_gym_venvs.sh`. +- **Pre-warm `LUSTRE_UV_CACHE` for the branch's `uv.lock`** (single process, + inside the job container — the source builds need `nvcc`): without it the + 16-node venv rebuild exceeds the idle-GPU reaper's *de facto* 60-minute + kill (observed twice; the 180-min exemption comment is valid per the + exemption guide but not honored beyond 60 — escalate to + @job-reaper-support with jobs 14516316/14521677 if 180 is ever needed). ## 4. What to compare (the perf read) diff --git a/swe/launch_swe_ab.sh b/swe/launch_swe_ab.sh index 56537d53785..aff2fc04f88 100755 --- a/swe/launch_swe_ab.sh +++ b/swe/launch_swe_ab.sh @@ -54,8 +54,13 @@ export EXP_SUFFIX="${EXP_SUFFIX:-swe-ab-${ARM}-$(date +%m%d%H%M)}" # unbaked VLLM_GYM worker venv. Forcing rebuild on both arms keeps setup cost # out of the A/B. export NRL_FORCE_REBUILD_VENVS=true -# Baked /opt/gym_venvs deps predate the Gym fork's floors; node-local rebuild. -export GYM_VENV_DIR="${GYM_VENV_DIR:-/tmp/nemo_gym_venvs}" +# Gym venvs: use the image-baked /opt/gym_venvs (present on EVERY node). +# A node-local GYM_VENV_DIR=/tmp/... does NOT work multi-node: the venv build +# runs only on the NemoGym actor's node while Gym spawns servers cluster-wide +# (learned from job 14542017). The fork's only dep-floor change vs the baked +# venvs is the aiohttp CVE bump (verified: swe_agents/vllm_model requirements +# unchanged), and editable installs serve the fork's *code* either way. +export GYM_VENV_DIR="${GYM_VENV_DIR:-/opt/gym_venvs}" # ---- Optional per-hop HTTP byte accounting ---------------------------------- if [ "${BYTES:-0}" = "1" ]; then From 1f567c9a1068188588393c0e872ae2c25faa5f4d Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Wed, 29 Jul 2026 09:43:50 -0700 Subject: [PATCH 41/44] fix(sc): skip reference logprobs when reference_policy_kl_penalty == 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setup.py inits the reference model only when the KL penalty is positive, but AdvantageConfig.reference_logprobs_field defaults to set — the SC then requests reference logprobs from a worker that never built reference_state_dict and dies with AttributeError in the first train step (SWE A/B job 14545431; the exemplar configs mask this with penalty 0.01). Null the field under the same condition. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- nemo_rl/algorithms/single_controller.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nemo_rl/algorithms/single_controller.py b/nemo_rl/algorithms/single_controller.py index 3e042857f0a..6f0db9142b5 100644 --- a/nemo_rl/algorithms/single_controller.py +++ b/nemo_rl/algorithms/single_controller.py @@ -92,6 +92,11 @@ def __init__( construct a bundle by hand (or with fakes) to bypass the real factories. """ self._advantage_cfg = AdvantageConfig() + # Mirror setup.py's init_reference_model condition: with no reference + # KL penalty the worker never builds reference_state_dict, so asking + # it for reference logprobs dies with AttributeError mid-step. + if master_config.loss_fn.reference_policy_kl_penalty <= 0: + self._advantage_cfg.reference_logprobs_field = None self._weight_sync_cfg = WeightSyncConfig() self._partition_id: str = bundle.partition_id self._diagnostics: bool = False From 4ba182d581731420f7b9483bcf385a02b0bddb50 Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Wed, 29 Jul 2026 11:02:01 -0700 Subject: [PATCH 42/44] docs(sc): add setup/try-it guide for gate-authoritative token capture Covers recursive clone with the published Gym fork pin (NVIDIA-NeMo/Gym pthombre/tq-gate-capture @ e3b3eac6), the token_capture config surface, the 2-GPU capture-enabled functional smoke, the SWE A/B tooling, gate metrics to watch, and env-gated debug switches. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- .../tq-gym-gate-authoritative-setup.md | 126 ++++++++++++++++++ docs/index.md | 1 + 2 files changed, 127 insertions(+) create mode 100644 docs/design-docs/tq-gym-gate-authoritative-setup.md diff --git a/docs/design-docs/tq-gym-gate-authoritative-setup.md b/docs/design-docs/tq-gym-gate-authoritative-setup.md new file mode 100644 index 00000000000..caddfc3b1f4 --- /dev/null +++ b/docs/design-docs/tq-gym-gate-authoritative-setup.md @@ -0,0 +1,126 @@ +# Token Capture (Gate-Authoritative): Setup and Try-It Guide + +How to set up and run the gate-authoritative token-in/token-out capture +pipeline from this branch. For the design itself see +[tq-gym-gate-authoritative.md](tq-gym-gate-authoritative.md); for the +stage-by-stage evidence see +[tq-gym-gate-authoritative-implementation-log.md](tq-gym-gate-authoritative-implementation-log.md). + +## What you get + +With `token_capture.enabled=true`, NeMo-Gym rollouts in the async +SingleController GRPO path run token-in/token-out: the Gym gate holds each +rollout's token lineage, vLLM workers stage per-call token deltas + logprobs +directly to the TransferQueue, and agent-facing messages plus the Ray return +become token-free. With `enabled=false` (the default) every legacy codepath +behaves exactly as before — the feature is dormant. + +## Prerequisites + +- The requirements of the async SingleController + NeMo-Gym path: the + feature only engages with `env.should_use_nemo_gym=true` and the async + vLLM generation backend. +- 2 GPUs for the smoke test below. +- `HF_TOKEN` exported (the functional test downloads the workplace-assistant + dataset from Hugging Face). + +## 1. Clone with submodules + +The feature spans this repo **and** a pinned NeMo-Gym fork branch. The +submodule gitlink points at commit `e3b3eac6` on +[`pthombre/tq-gate-capture`](https://github.com/NVIDIA-NeMo/Gym/tree/pthombre/tq-gate-capture) +of the public NVIDIA-NeMo/Gym repo (upstream main + a pinned rev of +[PR #2124](https://github.com/NVIDIA-NeMo/Gym/pull/2124) + the gate work), +so the standard recursive clone resolves it with no extra remotes: + +```bash +git clone --recurse-submodules git@github.com:NVIDIA-NeMo/RL.git +cd RL +git checkout pthombre/tq-gym-gate-capture +git submodule update --init --recursive +``` + +Verify the pin: `git submodule status 3rdparty/Gym-workspace/Gym` should +show `e3b3eac6...`. If it shows a `+` or a fetch error, re-run +`git submodule update --init --recursive` from the repo root. + +Environment setup is otherwise unchanged from +[installation](../about/installation.md) — the Gym fork is an editable uv +workspace member, so `uv run` picks it up automatically. + +## 2. Configuration + +All knobs live under `token_capture:` in the master config; defaults are on +`TokenCaptureConfig` +(`nemo_rl/algorithms/single_controller_utils/config.py`) and the exemplar +block is in `examples/configs/grpo_math_1B_single_controller.yaml`: + +```yaml +token_capture: + enabled: false # the only switch you must flip + staging_partition: "rollout_staging" + on_capture_failure: "continue" # continue: placeholder row | abort: fail rollout + mixed_weight_version_policy: "allow" + min_valid_fraction_per_group: null + registration_ttl_s: 3600.0 + staging_ttl_s: 3600.0 +``` + +Enable it on any SC + NeMo-Gym recipe with `++token_capture.enabled=true`. +Setup validation will reject configurations that enable capture without the +NeMo-Gym path or with `rollout_max_attempts_to_avoid_lp_nan != 1`. + +## 3. Smoke test (2 GPUs) + +The same SC + Gym functional test CI runs (see +`tests/functional/L1_Functional_Tests_SingleController.sh`): + +```bash +export HF_TOKEN=... +uv run --no-sync bash ./tests/functional/grpo_async_gym_single_controller.sh \ + ++token_capture.enabled=true +``` + +This prepares the workplace-assistant dataset, runs a short GRPO training +job through the gate, and asserts on the resulting metrics. Run it once +without the override first if you want a legacy-path baseline from the same +tree. + +## 4. Larger runs + +`swe/` contains the SWE-bench token-capture vs. legacy perf A/B: launch +tooling (`launch_swe_ab.sh`, `make_capture_config.py`), the runbook +(`SWE_RUN.md`), the pinned launch record (`EXPERIMENT_LAUNCH.md`), and +`aggregate_perf.py` for the comparison. `examples/swe_bench/` holds the +underlying async GRPO SWE recipe and launcher. + +## 5. What to watch + +Per-train-step `gate/*` metrics land in the SC logger (wandb/tensorboard): + +- `token_in_rate` — fraction of model calls served token-in (the happy + path). Drops indicate marker stripping or history edits by the agent; + the run stays correct (text-mode fallback) but wasteful. +- `fallback_rate` by cause, `capture_failure_rate`, + `digest_verify_failures`, `invalid_row_rate`, finalize latency, + `wv_spread`. + +Debug switches (env-gated, off by default): + +- `NRL_SC_DUMP_TRAIN_ROWS=` — dump canonical training rows at publish + time for legacy-vs-capture row diffs. +- `NRL_HTTP_BYTES_DIR` / `NG_HTTP_BYTES_DIR` — per-call HTTP byte counters + on the RL vLLM worker / Gym middleware respectively (the headline + bytes-per-token comparison vs. the token-echo path). + +## Troubleshooting + +- **Submodule fetch fails**: the gitlink must resolve to `e3b3eac6` on + NVIDIA-NeMo/Gym; check network access to github.com and re-run + `git submodule update --init --recursive`. +- **Everything falls back to text mode** (`token_in_rate` ≈ 0): the agent + or a proxy is stripping the `ng_call_id` marker from assistant messages, + or rewriting history above it. Correct but slow — see design doc § 3.3. +- **Placeholder-heavy groups**: check `capture_failure_rate` (worker-side + staging failures poison rollouts under `on_capture_failure: continue`) + and gate TTL expiries in the gate logs. diff --git a/docs/index.md b/docs/index.md index 6446c31f4f9..ed0c0292cba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -327,6 +327,7 @@ design-docs/env-vars.md design-docs/nemo-gym-integration.md design-docs/tq-gym-async-single-controller.md design-docs/tq-gym-gate-authoritative.md +design-docs/tq-gym-gate-authoritative-setup.md design-docs/tq-gym-gate-authoritative-implementation-log.md ``` From 8c942f6fcbade76b938c9773d83a39328ce7e39f Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Fri, 31 Jul 2026 14:25:34 -0700 Subject: [PATCH 43/44] feat(sc): migrate token capture onto the Gym tokidcap stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RL companion of the Gym branch tq-tokidcap-capture (submodule re-pinned here to b6051536 = upstream stack top 81ac2736/#2182 + our 7-commit staging/gate series). Executes docs/design-docs/tq-gym-tokidcap-migration.md; the working log with the workaround ledger and bump checklist is added as docs/design-docs/tq-gym-tokidcap-migration-log.md. Identity carrier switch (§3): drop the responses_create_params.metadata side-channel; rollout ids ride the run body as the opaque _ng_rollout_id key, agents stamp /ng-rollout/ on every model call via the stack's helpers, and the middleware-minted model_call_id becomes the call id — so the TQ sample id IS the capture key end to end. Registration stays create-only, pre-dispatch. Gate hosting config: TokenCaptureConfig grows lineage capacity (derived at setup from in-flight rollouts x max sequence length — finding M), a per-run control-plane bearer token (finding S), a hard per-call control deadline (S5 silent-stall finding), and the base capture dir the gate rides on (#2124-c1 workaround). nemo_gym.py injects the gate + capacity + auth into the policy model server, activates the base token capture layer, and opts every agent into correlation (token_id_capture_all_agents). Unchanged by design: TQTokenSink/TQTokenSource (keys are minted Gym-side), BlackboxFinalizer (the new terminal-aware linearize keeps its contract and surfaces unresolved retries as RebuildError -> the existing placeholder path), the worker capture hosting, and the weight-version fan-out. Dormant by default: everything is behind token_capture.enabled=false. Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- 3rdparty/Gym-workspace/Gym | 2 +- .../tq-gym-tokidcap-migration-log.md | 122 ++++++++++++++++++ .../grpo_math_1B_single_controller.yaml | 14 ++ .../single_controller_utils/config.py | 20 +++ .../single_controller_utils/setup.py | 31 +++++ nemo_rl/data_plane/tq_token_sink.py | 4 +- nemo_rl/environments/nemo_gym.py | 76 +++++++++-- nemo_rl/experience/rollout_manager.py | 6 +- tests/unit/data_plane/test_tq_token_sink.py | 4 +- 9 files changed, 258 insertions(+), 21 deletions(-) create mode 100644 docs/design-docs/tq-gym-tokidcap-migration-log.md diff --git a/3rdparty/Gym-workspace/Gym b/3rdparty/Gym-workspace/Gym index e3b3eac6c0c..b6051536d9a 160000 --- a/3rdparty/Gym-workspace/Gym +++ b/3rdparty/Gym-workspace/Gym @@ -1 +1 @@ -Subproject commit e3b3eac6c0cdfba9ce7b95e20cec13b04b17ca58 +Subproject commit b6051536d9ac569c853200051accf81ad8af0085 diff --git a/docs/design-docs/tq-gym-tokidcap-migration-log.md b/docs/design-docs/tq-gym-tokidcap-migration-log.md new file mode 100644 index 00000000000..f7893770878 --- /dev/null +++ b/docs/design-docs/tq-gym-tokidcap-migration-log.md @@ -0,0 +1,122 @@ +# Tokidcap Migration — Implementation Log + +Working log for executing [tq-gym-tokidcap-migration.md](tq-gym-tokidcap-migration.md) +(re-basing the gate-authoritative token-capture work onto the upstream Gym +token-id-capture stack). Companion to the MVP-era +[tq-gym-gate-authoritative-implementation-log.md](tq-gym-gate-authoritative-implementation-log.md), +which remains the record for the fork-based S1–S5 work. + +Conventions: every change lands here with its **status** +(`planned` → `in-progress` → `done ()` / `dropped ()`), the seam +or finding it serves, and any divergence from the plan doc. Un-gated behavior +changes (active with `token_capture.enabled=false`) get an explicit +**DISCLOSURE** marker. + +## Base facts (pinned) + +- Upstream stack: linear chain #2190→#2124→#2125→#2126→#2180→#2181→#2182, + verified 2026-07-31 in the submodule clone; **stack top = `81ac2736`** + (#2182, "require a bearer token on the token read route"). +- New Gym branch: `tq-tokidcap-capture`, cut from `81ac2736` (exact rev, + §6 finding G). Old fork branch `tq-gate-capture` (`e3b3eac6`, base + `fa0c2da3`) is left untouched as the cherry-pick donor. +- RL branch: work proceeds on `yukih/sc-entrypoint`; the §9b.1a companion-base + question (nano-SWE branch `3fcc69666`, owner Zhiyu Li) is an open + coordination point — capture commits are kept clean for later cherry-pick. +- Upstream asks: none landed as of 2026-07-31; every seam uses its §4 + workaround, contained in our modules. Ask outcomes shrink the diff later. + +## Workaround ledger (asks not landed) + +| Seam | Workaround in effect | Where | +|---|---|---| +| #2124-c1 install_token_sink honored | gate installs its manifest-observer sink by construction (we own the gate module); no base patch needed for worker-locus MVP | gate.py | +| #2124-c2 mark_incomplete on protocol | capture-poison flows through our CommitCoords/lineage, not the base sink protocol | staging/lineage.py | +| #2124-c3 commit_entry split | coords ingestion implemented in our gate module, feeding `RolloutLineage.record` on the base `LineageIndex` directly | gate.py | +| #2124-c4 schema_version | version carried in our staging records/receipts only | staging/records.py | +| #2126-c2 opaque rollout_id key | contained fork edit: accept an opaque `_ng_rollout_id` run-body key in `rollout_correlation.py` (shape-identical to the ask; collapses when it lands) — done (`1bdd7cdc`) | rollout_correlation.py | +| (new, to post as an ask) run-wide agent opt-in | `token_id_capture_all_agents` global key treats every agent as `token_id_capture=true` — the SC cannot enumerate agent servers configured via `config_paths` — done (`b6051536`) | base_responses_api_agent.py | +| #2180-c1 set_lineage_index | gate constructs a capacity-sized `LineageIndex` and replaces `sink._LINEAGE` before first request; attr name pinned in the bump checklist below | gate.py | +| #2180-c2 capacity config + eviction metric | comes free with the above (we construct the instance); eviction counter polled into gate metrics | gate.py | +| #2180-c3 resolver seam | not needed for MVP (no marker); Stage-2 exit kept in mind | — | +| #2181-c1 ng_capture hook | attached in `vllm_model/app.py` chat path (file we already edit for the gate); the highest-churn-risk edit, kept minimal | vllm_model/app.py | +| #2181-c2 required_prefix_token_ids contract | consumed as-is by the worker splice (proven code); rename risk noted in bump checklist | adapters/vllm.py | + +**Bump checklist** (things a stack rebase can silently break): `sink._LINEAGE` +attr name; `required_prefix_token_ids` field name; `model_call_id` mint site +(`base_responses_api_model.py` `_CaptureMiddleware`); `run_builder` / +`BuildNotes.unresolved_retries` shape; `/ng-rollout/` prefix regex. + +## Commit series (Gym branch `tq-tokidcap-capture`) + +Per plan §9b.2; each commit = a future stack PR. Status updated as they land. + +| # | Commit | Status | Notes | +|---|---|---|---| +| 1 | staging wire schema + digest (`staging/records.py`, `digest.py`, `protocols.py`; sink protocols renamed `StagingSink`/`StagingSource`) | done (`79540d2e`) | digest golden vectors unchanged; purity + records/digest tests in `test_token_capture_staging_core.py` (10 green) | +| 2 | terminal-aware linearize over `run_builder` (thin `staging/rebuild.py`) | done (`3d813fee`) | `snapshots_to_entries` + `LinearizedRow` kept; manifest walk deleted; terminal hint overrides token-mass pick (test proves the fork case); `unresolved_retries` → `RebuildError` → placeholder; 18 tests green | +| 3 | engine-blind capture core + vLLM adapter (`staging/capture.py`, `adapters/vllm.py`) | done (`232c7a43`) | module is identity-agnostic; rekey lands at call sites; 47 tests green | +| 4 | gate hosting, prefix serving, control plane (`gate.py`, `staging/lineage.py`, `control_routes.py` + bearer auth; seam edits in `vllm_model/app.py`) | done (`e1a9b4e7`) | identity switch complete (URL-prefix + `model_call_id`, marker plumbing gone); gate hosts capacity-sized eviction-counting `LineageIndex` via `sink._LINEAGE` replacement; coords ingestion feeds `LineageIndex.record`; bearer auth default-required; bounded client deadlines; conformance kit byte-exact through the `run_builder` linearize; e2e suite rehosted (ambiguity, auth, unknown-id rejection, flag-off dormancy); 199 tests green | +| 5 | observability (byte-counter middleware cherry-pick, unattributed-call counter; fallback-by-cause + eviction counter landed in commit 4) | done (`04597a3a`) | one adaptation: fork's `Dict` annotation → builtin `dict` (base dropped the import) | + +Deleted relative to the fork (base owns them): flat capture core +(`records`/`sink`/`store`/`config`/`routes`/`reader`/`source` + lazy +`__init__`), `memory_store.py`, most of `rebuild.py`, all marker plumbing +(`openai_utils.py` / `responses_converter.py` `*WithMarker` classes, +`find_marker`, `NG_CALL_ID_FIELD` message stamping), every fork edit to +`base_responses_api_model.py`. + +## RL-side changes (branch `yukih/sc-entrypoint`) + +| Change | Status | Notes | +|---|---|---| +| Re-pin submodule to `tq-tokidcap-capture` | in-progress | gitlink commits with the RL alignment; NRL_FORCE_REBUILD_VENVS on first run after | +| Identity carrier switch (drop `metadata["ng_rollout_id"]`; `_ng_rollout_id` run-body key → `/ng-rollout/`) | done (uncommitted) | rollout_manager `_build_inputs`, nemo_gym.py; verified `run_examples` posts rows verbatim so the key reaches the agent | +| Per-agent correlation opt-in | done (uncommitted) | SC sets `token_id_capture_all_agents=true` (Gym `b6051536`) | +| Gate hosting config: lineage capacity (derived: rollouts = 2×in-flight, tokens = rollouts×max seq len), bearer token (minted per run), capture dir (`/gym_token_capture`, the #2124-c1 workaround) | done (uncommitted) | TokenCaptureConfig + setup.py derivation + nemo_gym.py injection + exemplar YAML | +| Bounded control-plane deadline (`control_timeout_s`, default 60 s) | done (uncommitted) | `asyncio.wait_for` around every `_control` call (S5 silent-stall finding, H1 pulled into Stage 1) | +| Control-plane bearer auth on the client | done (uncommitted) | Authorization header on every `_control` call | +| Rekey staging keys to `{rollout_id}/{model_call_id}` | done (no code change) | keys minted Gym-side; worker/finalizer identity-agnostic | +| Finalizer: rebuild via `run_builder` wrapper, terminal hint + `unresolved_retries` → placeholder | done (no code change) | new Gym `linearize` keeps the signature; `unresolved_retries` surfaces as `RebuildError` → existing `rebuild_failed` placeholder path | +| Fix dead `staging_ttl_s` config | deferred | still unread (as in the fork MVP); H1 scope with the failure sweep | +| `uv.lock` regeneration for the new pin | done (uncommitted) | the stack top dropped Gym's `docs` dependency-group → lock update required; regenerated with uv 0.11.6 (the version family that wrote revision 3) for a minimal 934-line-deletion diff — uv 0.12 rewrites the whole lock to revision 4, avoid it for this repo | + +Note: the SC seals without an explicit `terminal_call_id` (it cannot know it); +the receipt's terminal defaults to the last-committed call (chronological), +which the finalizer's terminal-aware selection consumes. A background +sub-agent that commits after the main conversation's final call would win +the hint — accepted for Stage 1, revisit if the A/B row diff surfaces it. + +## Test gates + +- [ ] Gym: base capture suite + full unit suite green at every commit +- [ ] Gym: `staging/` purity test (subprocess import, no fastapi/ray/torch) +- [ ] Gym: conformance kit + gate e2e rehosted on stack request path +- [ ] Gym: flag-off byte-identity (capture disabled ⇒ legacy path unchanged) +- [ ] RL: capture unit tests (`--nemo-gym-only`) green on new pin +- [ ] RL: flag-off 2-GPU functional (`grpo_async_gym_single_controller.sh`) — + pin-bump regression +- [ ] RL: capture-enabled functional; fixed-seed A/B row diff; chaos smoke + +## Disclosures (active with the flag off) + +(none yet — all Gym-side behavior changes are behind `token_capture_gate.enabled` +or `NG_HTTP_BYTES_DIR`; the `_resolve_client` signature gained an optional +`rollout_id=None` parameter, a no-op when unset) + +## Divergences from the plan doc + +- **Gate activation requires the base token capture enabled with a real + capture dir** (`token_id_capture_enabled=true` + `token_id_capture_dir`) — + the #2124-c1 "activation without a capture dir" ask is not landed, and the + capture middleware only mints `model_call_id`/sets the capture context when + a token store exists. Cost: the base `capture_tokens` no-ops on the gate + path (worker strips token fields before the response), so the dir stays + ~empty; the RL launcher points it at the run's log dir. +- **Editing a user turn no longer breaks lineage.** The fork's fingerprint + covered the full history; the base's covers model-authored turns only, so + a harness that rewrites user/tool content keeps its chain (by design + upstream). The e2e "edited history" test now edits the assistant turn. +- **Fallback cause names** are `no_history` / `no_match` / `ambiguous` + (plan §8 sketched `no_prefix`/`no_match`/`ambiguity`/`multi_worker`; + `multi_worker` is not distinguishable at the gate and is deferred). diff --git a/examples/configs/grpo_math_1B_single_controller.yaml b/examples/configs/grpo_math_1B_single_controller.yaml index 9ab82b44413..db87aef172e 100644 --- a/examples/configs/grpo_math_1B_single_controller.yaml +++ b/examples/configs/grpo_math_1B_single_controller.yaml @@ -373,6 +373,20 @@ token_capture: # Gate-side cleanup backstops (seconds). registration_ttl_s: 3600.0 staging_ttl_s: 3600.0 + # Gym LineageIndex capacity (each in-flight rollout's cumulative tokens + # live in the gate process). null = derived from the training config: + # rollouts = 2 x max in-flight, tokens = rollouts x max sequence length. + # Size explicitly for agentic workloads with deep per-rollout call trees. + lineage_max_rollouts: null + lineage_max_tokens: null + # Bearer token for the gate's /ng-control/* routes. null = minted per run. + control_auth_token: null + # Hard deadline per control-plane call (gate death must surface as failed + # dispatches + placeholders, not a silent retry stall). + control_timeout_s: 60.0 + # Directory for the Gym base capture layer the gate rides on (stays + # essentially empty on the gate path). null = /gym_token_capture. + capture_dir: null cluster: gpus_per_node: 2 diff --git a/nemo_rl/algorithms/single_controller_utils/config.py b/nemo_rl/algorithms/single_controller_utils/config.py index 4eb85bd4c85..991d5c80206 100644 --- a/nemo_rl/algorithms/single_controller_utils/config.py +++ b/nemo_rl/algorithms/single_controller_utils/config.py @@ -77,6 +77,26 @@ class TokenCaptureConfig(BaseModel, extra="allow"): # Gate-side cleanup backstops. registration_ttl_s: float = 3600.0 staging_ttl_s: float = 3600.0 + # Gym LineageIndex capacity (finding M: it holds each in-flight rollout's + # full cumulative token sequence, and eviction of a live rollout silently + # degrades token-in to fallbacks). None = derived at setup from the + # training config: rollouts ≈ 2 × max in-flight; tokens ≈ rollouts × max + # sequence length. Set explicitly for agentic workloads whose per-rollout + # call trees hold more than one context of tokens. + lineage_max_rollouts: Optional[int] = None + lineage_max_tokens: Optional[int] = None + # Bearer token for the gate's /ng-control/* routes (finding S). None = + # minted per run at setup; set explicitly only for multi-controller + # setups that must share one gate. + control_auth_token: Optional[str] = None + # Hard deadline per control-plane call (S5 finding: gate death must + # surface as a failed dispatch, not a silent retry stall). + control_timeout_s: float = 60.0 + # Directory for the Gym base capture layer the gate rides on (#2124-c1: + # the capture middleware only engages with a capture dir configured; the + # dir stays essentially empty on the gate path). None = derived at setup + # under the run's log dir. + capture_dir: Optional[str] = None class MasterConfig(BaseModel, extra="allow"): diff --git a/nemo_rl/algorithms/single_controller_utils/setup.py b/nemo_rl/algorithms/single_controller_utils/setup.py index 9782bfcf7ea..224573fbba7 100644 --- a/nemo_rl/algorithms/single_controller_utils/setup.py +++ b/nemo_rl/algorithms/single_controller_utils/setup.py @@ -21,6 +21,7 @@ from __future__ import annotations +import os from concurrent.futures import ThreadPoolExecutor from dataclasses import dataclass from typing import Any, Optional @@ -307,6 +308,36 @@ def setup_single_controller( "nemo_rl.models.generation.vllm.vllm_worker_async.VllmAsyncGenerationWorker" ] = PY_EXECUTABLES.VLLM_GYM + # Fill the derived gate-hosting fields (see TokenCaptureConfig): + # a per-run control-plane bearer token, the base capture dir the + # gate rides on, and LineageIndex capacity sized from the training + # config (finding M: eviction of a live rollout must not happen + # under normal operation). + if token_capture_cfg.control_auth_token is None: + # Deferred import: only needed on the capture path. + import secrets + + token_capture_cfg.control_auth_token = secrets.token_hex(32) + if token_capture_cfg.capture_dir is None: + token_capture_cfg.capture_dir = os.path.abspath( + os.path.join( + master_config.logger.get("log_dir") or "logs", + "gym_token_capture", + ) + ) + if token_capture_cfg.lineage_max_rollouts is None: + group_size = grpo_config["num_generations_per_prompt"] + in_flight = ( + master_config.async_rl.max_buffered_rollouts + + master_config.async_rl.max_inflight_prompts + ) * group_size + token_capture_cfg.lineage_max_rollouts = 2 * in_flight + if token_capture_cfg.lineage_max_tokens is None: + token_capture_cfg.lineage_max_tokens = ( + token_capture_cfg.lineage_max_rollouts + * int(master_config.policy["max_total_sequence_length"]) + ) + set_seed(grpo_config["seed"]) # ========================== diff --git a/nemo_rl/data_plane/tq_token_sink.py b/nemo_rl/data_plane/tq_token_sink.py index c827750964a..0f83c1e9fc9 100644 --- a/nemo_rl/data_plane/tq_token_sink.py +++ b/nemo_rl/data_plane/tq_token_sink.py @@ -63,7 +63,7 @@ def _call_dp(dp_client: Any, method_name: str, **kwargs: Any) -> Any: class TQTokenSink: - """Gym ``TokenSink`` over ``DataPlaneClient.put_samples``. + """Gym ``StagingSink`` over ``DataPlaneClient.put_samples``. ``stage`` is synchronous and returns only after TQ acknowledged the write, so the capture layer's fail-closed ordering (bytes durable before @@ -136,7 +136,7 @@ def clear(self, staging_keys: list[str]) -> None: class TQTokenSource: - """Gym ``TokenSource`` over ``DataPlaneClient.get_samples``. + """Gym ``StagingSource`` over ``DataPlaneClient.get_samples``. Rows are fetched one key at a time (deltas are jagged across calls) in the order requested. A missing or unreadable row raises ``KeyError`` per diff --git a/nemo_rl/environments/nemo_gym.py b/nemo_rl/environments/nemo_gym.py index b80a98be9df..9aebbec9963 100644 --- a/nemo_rl/environments/nemo_gym.py +++ b/nemo_rl/environments/nemo_gym.py @@ -11,6 +11,7 @@ # 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 asyncio import os import subprocess from pathlib import Path @@ -89,9 +90,11 @@ class NemoGymConfig(TypedDict): # Gym control-plane server name (the model server hosting the gate) and the -# metadata key rollout ids ride on (defined in Gym's token_id_capture.gate). +# opaque run-body key rollout ids ride on (Gym's ROLLOUT_ID_KEY_NAME): the +# agent derives the id from the run body and stamps /ng-rollout/ on every +# model call, so the TQ sample id IS the capture key end to end. _POLICY_SERVER_NAME = "policy_model" -_NG_ROLLOUT_ID_METADATA_KEY = "ng_rollout_id" +_NG_ROLLOUT_ID_BODY_KEY = "_ng_rollout_id" def _detect_invalid_tool_call_and_malformed_thinking( @@ -258,6 +261,8 @@ def _spinup(self) -> None: token_capture and token_capture.get("enabled") ) self._server_client = None + self._control_headers: Dict[str, str] = {} + self._control_timeout_s = 60.0 if self._token_capture_enabled: if self.rollout_max_attempts_to_avoid_lp_nan != 1: raise ValueError( @@ -274,7 +279,41 @@ def _spinup(self) -> None: policy_overrides["token_capture_gate"] = { "enabled": True, "registration_ttl_s": token_capture["registration_ttl_s"], + # Finding M: the LineageIndex holds each in-flight rollout's + # cumulative tokens; capacity is sized from the training + # config at setup, never left at the eval-sized defaults. + "lineage_max_rollouts": token_capture["lineage_max_rollouts"], + "lineage_max_tokens": token_capture["lineage_max_tokens"], + # Finding S: control routes are bearer-authed, + # default-required; the token is minted per run at setup. + "control_auth_token": token_capture["control_auth_token"], } + # #2124-c1 workaround: the capture middleware mints model_call_id + # (and sets the capture context the gate keys on) only when the + # base token capture is active, which requires a capture dir. + # The base's own capture_tokens no-ops on the gate path (the + # worker strips token fields before responding), so the dir + # stays essentially empty. + initial_global_config_dict["token_id_capture_enabled"] = True + initial_global_config_dict["token_id_capture_dir"] = token_capture[ + "capture_dir" + ] + # Agents apply the /ng-rollout/ correlation prefix for token + # capture only when they opt in (the global enabled switch alone + # gates the infrastructure, not the prefix). In an RL training + # run every agent must correlate, and the SC cannot enumerate + # agent servers configured via config_paths — so flip the + # run-wide opt-in the Gym branch adds for exactly this case. + initial_global_config_dict["token_id_capture_all_agents"] = True + self._control_headers = { + "Authorization": f"Bearer {token_capture['control_auth_token']}" + } + # S5 chaos finding: Gym's shared request() retries connection + # errors indefinitely; a dead gate must surface as a failed + # dispatch (placeholders + TTL), not a silent stall. + self._control_timeout_s = float( + token_capture.get("control_timeout_s") or 60.0 + ) self.rh = RunHelper() self.rh.start( @@ -306,9 +345,23 @@ def _control_client(self): return self._server_client async def _control(self, method: str, path: str, **kwargs: Any) -> dict: - response = await self._control_client().request( - server_name=_POLICY_SERVER_NAME, url_path=path, method=method, **kwargs - ) + headers = {**kwargs.pop("headers", {}), **self._control_headers} + try: + response = await asyncio.wait_for( + self._control_client().request( + server_name=_POLICY_SERVER_NAME, + url_path=path, + method=method, + headers=headers, + **kwargs, + ), + timeout=self._control_timeout_s, + ) + except asyncio.TimeoutError: + raise RuntimeError( + f"gate control call {method} {path} exceeded " + f"{self._control_timeout_s}s (gate unreachable or stalled)" + ) from None if response.status != 200: raise RuntimeError( f"gate control call {method} {path} failed: " @@ -347,13 +400,10 @@ async def run_rollouts( timer = Timer() if self._token_capture_enabled: - # Receipt mode: register the gate-registered ids riding each - # row's metadata before dispatch; seal at completion. + # Receipt mode: register the ids riding each row's run body + # before dispatch; seal at completion. rollout_ids = [ - example["responses_create_params"]["metadata"][ - _NG_ROLLOUT_ID_METADATA_KEY - ] - for example in nemo_gym_examples + example[_NG_ROLLOUT_ID_BODY_KEY] for example in nemo_gym_examples ] await self.register_rollouts(rollout_ids) @@ -442,9 +492,7 @@ async def _postprocess_receipt_mode( assert isinstance(nemo_gym_result, dict), ( f"Hit a non-successful response when querying NeMo Gym for rollouts: {nemo_gym_result}" ) - rollout_id = nemo_gym_row["responses_create_params"]["metadata"][ - _NG_ROLLOUT_ID_METADATA_KEY - ] + rollout_id = nemo_gym_row[_NG_ROLLOUT_ID_BODY_KEY] try: receipt = await self._control( "POST", diff --git a/nemo_rl/experience/rollout_manager.py b/nemo_rl/experience/rollout_manager.py index c9b0c42067b..b141b60a905 100644 --- a/nemo_rl/experience/rollout_manager.py +++ b/nemo_rl/experience/rollout_manager.py @@ -493,8 +493,10 @@ def _build_inputs( row = copy.deepcopy(template_row) row["_rowidx"] = i if rollout_ids is not None: - metadata = row["responses_create_params"].setdefault("metadata", {}) - metadata["ng_rollout_id"] = rollout_ids[i] + # Opaque run-body carrier (Gym's _ng_rollout_id key): the agent + # derives the id from the run body and stamps /ng-rollout/ + # on every model call, so the TQ sample id IS the capture key. + row["_ng_rollout_id"] = rollout_ids[i] rows.append(row) return rows diff --git a/tests/unit/data_plane/test_tq_token_sink.py b/tests/unit/data_plane/test_tq_token_sink.py index d91bc1abb02..d543756a084 100644 --- a/tests/unit/data_plane/test_tq_token_sink.py +++ b/tests/unit/data_plane/test_tq_token_sink.py @@ -33,10 +33,10 @@ run_sink_source_conformance, ) from nemo_gym.token_id_capture.staging.protocols import ( # noqa: E402 - TokenSink as TokenSinkProtocol, + StagingSink as TokenSinkProtocol, ) from nemo_gym.token_id_capture.staging.protocols import ( # noqa: E402 - TokenSource as TokenSourceProtocol, + StagingSource as TokenSourceProtocol, ) from nemo_rl.data_plane.tq_token_sink import ( # noqa: E402 From 624bb277d92a28bcaa846ca4ab75fe2ca365214f Mon Sep 17 00:00:00 2001 From: Pranav Prashant Thombre Date: Fri, 31 Jul 2026 14:51:30 -0700 Subject: [PATCH 44/44] chore(sc): update uv.lock for the tokidcap-stack submodule pin The new Gym base drops Gym's docs dependency-group, so the locked package set shrinks accordingly (934 deletions, no other changes; lockfile revision unchanged). Co-Authored-By: Claude Fable 5 Signed-off-by: Pranav Prashant Thombre --- uv.lock | 934 -------------------------------------------------------- 1 file changed, 934 deletions(-) diff --git a/uv.lock b/uv.lock index 3750f3a54a4..873b14452ef 100644 --- a/uv.lock +++ b/uv.lock @@ -220,29 +220,13 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/57/be/5afd201cc0ab139029aadb75392efe85a293403d9dd3a3226161c21ce00c/aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86", size = 506269, upload-time = "2026-07-23T01:54:49.075Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/dec8189d62b45ade009f6792a2264b942a90cb88aeaf181239933cd72c3c/aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627", size = 515166, upload-time = "2026-07-23T01:54:51.894Z" }, { url = "https://files.pythonhosted.org/packages/28/24/2854869d29ed8a8b19d74f9ec6629515f7e04d02dd329d9d179201e58e47/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82", size = 486263, upload-time = "2026-07-23T01:54:54.223Z" }, { url = "https://files.pythonhosted.org/packages/d4/dd/57187c8be2a35aea65eaee3bd2c3dcbbcf0204f5106c89637e3610380cd1/aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c", size = 492299, upload-time = "2026-07-23T01:54:56.236Z" }, { url = "https://files.pythonhosted.org/packages/b9/11/06ae6ed8f0d414edf4068861e233d8fe23ee699bfd4b3ceb8663db948a62/aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f", size = 502235, upload-time = "2026-07-23T01:54:58.377Z" }, - { url = "https://files.pythonhosted.org/packages/7e/a3/559639c34a345d2cf7c52dff6838119f2eaf29eb508227b5b83f573af813/aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80", size = 750883, upload-time = "2026-07-23T01:55:00.65Z" }, - { url = "https://files.pythonhosted.org/packages/91/cd/41e131f13afd1e7b0172a9d9eda085ef90eb8439f41f0d279db81ed3ae60/aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0", size = 508473, upload-time = "2026-07-23T01:55:02.945Z" }, - { url = "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf", size = 509190, upload-time = "2026-07-23T01:55:05.173Z" }, { url = "https://files.pythonhosted.org/packages/97/21/6464573e53d69672cc1eada3e5c5cb2d2efa82701e8305a0f2047a576967/aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd", size = 1761478, upload-time = "2026-07-23T01:55:07.383Z" }, - { url = "https://files.pythonhosted.org/packages/1a/81/d217043a4c17fbce360905e3b2bdd20139ebc9a2de836d035d179c4da006/aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807", size = 1735092, upload-time = "2026-07-23T01:55:09.803Z" }, - { url = "https://files.pythonhosted.org/packages/a1/66/e13a02d0eeb1a9a502402a977abb4e4abff9fe4051c26f80558c57a7c975/aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8", size = 1800546, upload-time = "2026-07-23T01:55:12.012Z" }, - { url = "https://files.pythonhosted.org/packages/26/5e/57d42fca1d18cb5acc1cad945d017fabc5d6ae71d8a08ad66be8dc3ee544/aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24", size = 1895250, upload-time = "2026-07-23T01:55:14.357Z" }, { url = "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5", size = 1789289, upload-time = "2026-07-23T01:55:16.668Z" }, - { url = "https://files.pythonhosted.org/packages/cd/0f/cf16bcf56896981c1a0319f5d5db9337994b5165730c48a8fa07e9b34be6/aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4", size = 1586706, upload-time = "2026-07-23T01:55:18.913Z" }, { url = "https://files.pythonhosted.org/packages/fe/6f/76eac12a7f2480e1e304f842efdb07db33256b0d9165b866b6ef0806c202/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9", size = 1724652, upload-time = "2026-07-23T01:55:21.296Z" }, - { url = "https://files.pythonhosted.org/packages/39/b6/19c8c592baeeb94b75f966547d40c02ac7590902306ec5863d5c027cf506/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1", size = 1756239, upload-time = "2026-07-23T01:55:23.705Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c9/4e9383150296f97f873b680c4de8fb2cd88608fb9f48c79edcb111611abc/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371", size = 1769161, upload-time = "2026-07-23T01:55:26.082Z" }, - { url = "https://files.pythonhosted.org/packages/aa/1e/147bdc6cc5de5f3ab011be8bf5d6e786633249f22c20bae06f85e45f5387/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde", size = 1578759, upload-time = "2026-07-23T01:55:28.846Z" }, - { url = "https://files.pythonhosted.org/packages/fd/31/78388a9d6040ece2e11df62ea229a822cf5e52d238374b220ae9975b2623/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e", size = 1792025, upload-time = "2026-07-23T01:55:31.457Z" }, { url = "https://files.pythonhosted.org/packages/03/51/a3d29fdf2c25d796746af8ad6fe56a45d6256c38b0a8a2ed752e1160b3a2/aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71", size = 1768477, upload-time = "2026-07-23T01:55:33.87Z" }, - { url = "https://files.pythonhosted.org/packages/29/a6/442e18b5afeade534d877a2dc3c3e392aff8d49787890b0cf84790410267/aiohttp-3.14.3-cp313-cp313-win32.whl", hash = "sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0", size = 451069, upload-time = "2026-07-23T01:55:36.121Z" }, - { url = "https://files.pythonhosted.org/packages/9d/69/3d876ac02659f271cf7f6769f14a8e3de5b6e888ed8b5a7e998086a4cec8/aiohttp-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883", size = 476518, upload-time = "2026-07-23T01:55:38.303Z" }, - { url = "https://files.pythonhosted.org/packages/b2/0e/50d6e6471cd31edce8b282bdec59375a3a69124d8a989a0b1313355cae52/aiohttp-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2", size = 447676, upload-time = "2026-07-23T01:55:40.451Z" }, ] [[package]] @@ -372,12 +356,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/6f/60/1e787a0b5ebf318483235be2a689ee367173983067e441b8379564f667c0/apache_tvm_ffi-0.1.9.tar.gz", hash = "sha256:d2d402587e8906de0a07f4746aa78f3d452c7efe3625d4bb39ac2ad693bce530", size = 2513731, upload-time = "2026-02-27T19:28:06.602Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/f2/b8c4b151169f6d7ba8773c8af68b2e0c1013d7fb3f1bdf87573f47157ce9/apache_tvm_ffi-0.1.9-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:49e52350b0470654847de752e65603b604a4d3323e7e9f5e8a982f44acc4c143", size = 2041756, upload-time = "2026-02-27T19:27:23.931Z" }, { url = "https://files.pythonhosted.org/packages/a7/c0/6d3d54f50012255b41bc3e24944c086f63c4707c8686c7c6780e9283eb96/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d503029e66c43b1a1cb1a42a1e9bb428c8a28dcbdec31c28e705472ca648a3a", size = 2203712, upload-time = "2026-02-27T19:27:25.867Z" }, { url = "https://files.pythonhosted.org/packages/c6/dd/2bab4c6cd86257dbf99e93452a1af833113f8dc3e25a25579f6e4e4c8a94/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28241371934ea8af10d5067087ba1229ebddded7b2c02d33a258ec2a96df8c46", size = 2299704, upload-time = "2026-02-27T19:27:27.477Z" }, { url = "https://files.pythonhosted.org/packages/7a/4a/b469bcb2e1014cb84d336d2a59f42958a058251c577a4c2680cacad346e2/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:87cacce81df55685fc6a76e1e3c5db1200e85e87bf5974b692c59d131b7bc622", size = 2130865, upload-time = "2026-02-27T19:27:29.092Z" }, { url = "https://files.pythonhosted.org/packages/70/ef/5402da5d37f5270fd88ea0348acca78dba9be8bdbf6c2bcae0935eb03ef1/apache_tvm_ffi-0.1.9-cp312-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f45eb43499acac45ff6c93564f0ff2d3ca27b69656d540fd56ce59d51c0b4c65", size = 2278991, upload-time = "2026-02-27T19:27:30.729Z" }, - { url = "https://files.pythonhosted.org/packages/b5/23/1b7dc5f0807f83098183a57db6ee85b2c93b646d74a6e03781c9208aaeb0/apache_tvm_ffi-0.1.9-cp312-abi3-win_amd64.whl", hash = "sha256:d1dcf4c041d5ec05e3da1d545800c33cdbb95c113baa7705085ff79fa262752b", size = 1973200, upload-time = "2026-02-27T19:27:32.367Z" }, ] [[package]] @@ -393,12 +375,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/6d/3d/4b9226cd45aa800a6904603dda9b323d728f3c3869952a673f3483b78b19/apache_tvm_ffi-0.1.11.tar.gz", hash = "sha256:153cd2c5a9717804cb0bcd9b2709f22a1e5f80ed05b5a490faf5949b136eedba", size = 2798354, upload-time = "2026-05-04T17:48:43.852Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/9d/0f81ca556e5836b3ca64818cdae3f47dc7822bd35d22ddef7a54106d801d/apache_tvm_ffi-0.1.11-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:6ae51cc7df415b5f373a9df4baa1165a65608e519bea81e7dd23428f00eeb689", size = 2418793, upload-time = "2026-05-04T17:47:57.879Z" }, { url = "https://files.pythonhosted.org/packages/2a/a9/f48e5dd4ae1f6f0c5ffac259c0a9531b7d6a7c0a4c45bc2229d55de6adf8/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:da2c8d07fdc737d1ba75f4de25c29f156905b9dc980f1da90c395b4db525f522", size = 2605176, upload-time = "2026-05-04T17:47:59.676Z" }, { url = "https://files.pythonhosted.org/packages/36/99/2848df4e8ed5bf51df1d286d1718510584fa61e88adbc9c5b23d71b38f7c/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:78aa1857b04a2ea718317041ab3f01288b3d496e6036eb1b99ebdc9da0fdaef5", size = 2725887, upload-time = "2026-05-04T17:48:01.381Z" }, { url = "https://files.pythonhosted.org/packages/7d/80/963c991934a4eb0fa0c0178f51963333fe14a96b732009da642b6bf6b42e/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a8b845c8dff498fb981c1dda36c954549204191b485a385845e604966594d0b2", size = 2513121, upload-time = "2026-05-04T17:48:03.43Z" }, { url = "https://files.pythonhosted.org/packages/4d/18/95569107ee83619d61a3bb0d28743a0599f85c5161981e3e098c82c2b185/apache_tvm_ffi-0.1.11-cp312-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2843f084cdc94dedacd8b257a395a2b71b8a3dc7fc99711b148bf1d161983128", size = 2697683, upload-time = "2026-05-04T17:48:05.222Z" }, - { url = "https://files.pythonhosted.org/packages/dc/99/f352cf1cce8f6f05584c4adf11de9eca07e6d217229bad6af35fb372926c/apache_tvm_ffi-0.1.11-cp312-abi3-win_amd64.whl", hash = "sha256:bd67e03759d25ff59f4e0ed9c8630a16872afc9dd8792f46ac3c927554015e60", size = 2365545, upload-time = "2026-05-04T17:48:07.295Z" }, ] [[package]] @@ -407,21 +387,10 @@ version = "0.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a9/9d/912fefab0e30aee6a3af8a62bbea4a81b29afa4ba2c973d31170620a26de/ast_serialize-0.3.0.tar.gz", hash = "sha256:1bc3ca09a63a021376527c4e938deedd11d11d675ce850e6f9c7487f5889992b", size = 60689, upload-time = "2026-04-30T23:24:48.104Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/93/72abad83966ed6235647c9f956417dc1e17e997696388521910e3d1fa3f4/ast_serialize-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ec2fafa5e4313cc8feed96e436ebe19ac7bc6fa41fbc2827e826c48b9e4c3a9", size = 1190024, upload-time = "2026-04-30T23:24:22.486Z" }, - { url = "https://files.pythonhosted.org/packages/85/4f/eb88584b2f0234e581762011208ca203252bf6c98e59b4769daa571f3576/ast_serialize-0.3.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef6d3c08b7b4cd29b48410338e134764a00e76d25841eb02c1084e868c888ecc", size = 1178633, upload-time = "2026-04-30T23:24:24.35Z" }, { url = "https://files.pythonhosted.org/packages/56/51/cf1ec1ff3e616373d0dcbd5fad502e0029dc541f13ab642259762a7d127f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d841424f41b886e98044abc80769c14a956e6e5ccd5fb5b0d9f5ead72be18a4", size = 1241351, upload-time = "2026-04-30T23:24:25.987Z" }, - { url = "https://files.pythonhosted.org/packages/0d/44/68fcf50478cf1093f2d423f034ae06453122c8b415d8e21a44668eca485d/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d21453734ad39367ede5d37efe4f59f830ce1c09f432fc72a90e368f77a4a3e7", size = 1239582, upload-time = "2026-04-30T23:24:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/9d/c1/a6c9fa284eceb5fc6f21347e968445a051d7ca2c4d34e6a04314646dbcee/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5e110cdce2a347e1dd987529c88ef54d26f67848dce3eba1b3b2cc2cf085c94", size = 1448853, upload-time = "2026-04-30T23:24:29.534Z" }, - { url = "https://files.pythonhosted.org/packages/23/5f/8ad3829a09e4e8c5328a53ce7d4711d660944e3e164c5f6abcc2c8f27167/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6e23a98e57560a055f5c4b68700a0fd5ce483d2814c23140b3638c7f5d1e61", size = 1262204, upload-time = "2026-04-30T23:24:31.482Z" }, { url = "https://files.pythonhosted.org/packages/25/13/44aa28d97f10e25247e8576b5f6b2795d4fa1a80acc88acc942c508d06f7/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c9e763d70293d65ce1e1ea8c943140c68d0953f0268c7ee0998f2e07f77dd0", size = 1266458, upload-time = "2026-04-30T23:24:33.088Z" }, - { url = "https://files.pythonhosted.org/packages/d8/58/b3a8be3777cd3744324fd5cec0d80d37cd96fc7cbb0fb010e03dff1e870f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4388a1796c228f1ce5c391426f7d21a0003ad3b47f677dbeded9bd1a85c7209f", size = 1308700, upload-time = "2026-04-30T23:24:34.657Z" }, { url = "https://files.pythonhosted.org/packages/13/03/f8312d6b57f5471a9dc7946f22b8798a1fc296d38c25766223aacadec42c/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5283cdcc0c64c3d8b9b688dc6aaa012d9c0cf1380a7f774a6bae6a1c01b3205a", size = 1416724, upload-time = "2026-04-30T23:24:36.562Z" }, - { url = "https://files.pythonhosted.org/packages/50/5d/13fc3789a7abac00559da2e2e9f386db4612aa1f84fc53d09bf714c37545/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f5ef88cc5842a5d7a6ac09dc0d5fc2c98f5d276c1f076f866d55047ce886785b", size = 1515441, upload-time = "2026-04-30T23:24:38.018Z" }, - { url = "https://files.pythonhosted.org/packages/eb/b9/7ab43fc7a23b1f970281093228f5f79bed6edeed7a3e672bde6d7a832a58/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cc14bf402bdc0978594ecce783793de2c7470cd4f5cd7eb286ca97ed8ff7cba9", size = 1510522, upload-time = "2026-04-30T23:24:39.798Z" }, { url = "https://files.pythonhosted.org/packages/56/ec/d75fc2b788d319f1fad77c14156896f31afdfc68af85b505e5bdebcb9592/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11eae0cf1b7b3e0678133cc2daa974ea972caf02eb4b3aa062af6fa9acd52c57", size = 1460917, upload-time = "2026-04-30T23:24:41.305Z" }, - { url = "https://files.pythonhosted.org/packages/95/74/f99c81193a2725911e1911ae567ed27c2f2419332c7f3537366f9d238cac/ast_serialize-0.3.0-cp39-abi3-win32.whl", hash = "sha256:2db3dd99de5e6a5a11d7dda73de8750eb6e5baaf25245adf7bdcfe64b6108ae2", size = 1067804, upload-time = "2026-04-30T23:24:43.091Z" }, - { url = "https://files.pythonhosted.org/packages/16/81/76af00c47daa151e89f98ae21fbbcb2840aaa9f5766579c4da76a3c57188/ast_serialize-0.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:a2cd125adccf7969470621905d302750cd25951f22ea430d9a25b7be031e5549", size = 1105561, upload-time = "2026-04-30T23:24:44.578Z" }, - { url = "https://files.pythonhosted.org/packages/bd/46/d3ec57ad500f598d1554bd14ce4df615960549ab2844961bc4e1f5fbd174/ast_serialize-0.3.0-cp39-abi3-win_arm64.whl", hash = "sha256:0dd00da29985f15f50dc35728b7e1e7c84507bccfea1d9914738530f1c72238a", size = 1077165, upload-time = "2026-04-30T23:24:46.377Z" }, ] [[package]] @@ -469,14 +438,10 @@ version = "17.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/f0/8c8dca97ae0cf00e8e2a53bb5cb9aca5fd484f585ef3e9b412200aff3ebd/av-17.0.1.tar.gz", hash = "sha256:fbcbd4aa43bca6a8691816283112d1659a27f407bbeb66d1397023691339f5d4", size = 4411938, upload-time = "2026-04-18T17:12:34.29Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/82/e7007dcef7bd2d2c377e2e85977701384f42d19fc808c2ccb3a99eaf58f2/av-17.0.1-cp311-abi3-macosx_11_0_x86_64.whl", hash = "sha256:987f4f46ceae4da6c614dcbd2b8149be9dbf680c3bb7a6841c58af9cff4d9230", size = 23238802, upload-time = "2026-04-18T17:11:51.166Z" }, - { url = "https://files.pythonhosted.org/packages/6b/aa/858b09a08ea6f83f91be44b5a5adad13ae8d9ac8b80fda27e73c24bfb160/av-17.0.1-cp311-abi3-macosx_14_0_arm64.whl", hash = "sha256:d97f54e55b18a74912f479c1978aadd1341d38d892dee95bb5c2f2dccfa72f32", size = 18709338, upload-time = "2026-04-18T17:11:53.286Z" }, { url = "https://files.pythonhosted.org/packages/a8/8b/8de3fd21c4b0b74d44337421abeab0e71462337fb6a28fff888e0c356cbd/av-17.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e6eee84afa48d0e9321047cd3e4facd44b401493f6bdc753e2e1d1e7c9e6d13e", size = 34007351, upload-time = "2026-04-18T17:11:56.116Z" }, { url = "https://files.pythonhosted.org/packages/02/28/167b291356c2cc315a2d62a95b0ceace72b5b0bf547de30b89313110f032/av-17.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c58c71bffd9383908c85695ac61d3184c668accb04a5bd1b262e0fb8d09f60a5", size = 36345295, upload-time = "2026-04-18T17:11:59.125Z" }, { url = "https://files.pythonhosted.org/packages/04/fa/aae56f2ff2c204c408641e1120f5ca5ce9c3390cf5362245c6f1158704b5/av-17.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:42d6745d30a410ec9b22aef79a52a7ab5a001eb8f5adfd952946606a30983318", size = 35183754, upload-time = "2026-04-18T17:12:01.697Z" }, { url = "https://files.pythonhosted.org/packages/ba/bd/776046f27093aef80155a204ca7d82a887ae4ee72ba4ef8411b46ea7898c/av-17.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3ed6bcd7021fe55832f95b8ef78dd01a4cb21faf3cd71f1e1bf4f20bf100b278", size = 37430809, upload-time = "2026-04-18T17:12:04.231Z" }, - { url = "https://files.pythonhosted.org/packages/d9/d5/3261bd2c6b7f6c0aa8379fc970d1ecf496330990b992ad28607785074268/av-17.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:9af524e8632a54032e361d6b88895bd3e7c6212ca560de60f5ccc525323c764c", size = 28889649, upload-time = "2026-04-18T17:12:07.04Z" }, - { url = "https://files.pythonhosted.org/packages/98/39/381104e427a0c7231d2ec0d25d538d58fc20fc0458846b95860d3ef8073b/av-17.0.1-cp311-abi3-win_arm64.whl", hash = "sha256:50e58a473d65ea29b645e45c9fd8518a6783737135683ecc40571a91592bdfe4", size = 21918412, upload-time = "2026-04-18T17:12:09.312Z" }, ] [[package]] @@ -516,30 +481,14 @@ version = "1.0.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/75/aa/abcd75e9600987a0bc6cfe9b6b2ff3f0e2cb08c170addc6e76035b5c4cb3/blake3-1.0.8.tar.gz", hash = "sha256:513cc7f0f5a7c035812604c2c852a0c1468311345573de647e310aca4ab165ba", size = 117308, upload-time = "2025-10-14T06:47:48.83Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/b8/11de9528c257f7f1633f957ccaff253b706838d22c5d2908e4735798ec01/blake3-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:46dc20976bd6c235959ef0246ec73420d1063c3da2839a9c87ca395cf1fd7943", size = 347771, upload-time = "2025-10-14T06:46:04.248Z" }, - { url = "https://files.pythonhosted.org/packages/50/26/f7668be55c909678b001ecacff11ad7016cd9b4e9c7cc87b5971d638c5a9/blake3-1.0.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d17eb6382634b3a5bc0c0e0454d5265b0becaeeadb6801ed25150b39a999d0cc", size = 325431, upload-time = "2025-10-14T06:46:06.136Z" }, { url = "https://files.pythonhosted.org/packages/77/57/e8a85fa261894bf7ce7af928ff3408aab60287ab8d58b55d13a3f700b619/blake3-1.0.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19fc6f2b7edab8acff6895fc6e38c19bd79f4c089e21153020c75dfc7397d52d", size = 370994, upload-time = "2025-10-14T06:46:07.398Z" }, - { url = "https://files.pythonhosted.org/packages/62/cd/765b76bb48b8b294fea94c9008b0d82b4cfa0fa2f3c6008d840d01a597e4/blake3-1.0.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f54cff7f15d91dc78a63a2dd02a3dccdc932946f271e2adb4130e0b4cf608ba", size = 374372, upload-time = "2025-10-14T06:46:08.698Z" }, - { url = "https://files.pythonhosted.org/packages/36/7a/32084eadbb28592bb07298f0de316d2da586c62f31500a6b1339a7e7b29b/blake3-1.0.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7e12a777f6b798eb8d06f875d6e108e3008bd658d274d8c676dcf98e0f10537", size = 447627, upload-time = "2025-10-14T06:46:10.002Z" }, - { url = "https://files.pythonhosted.org/packages/a7/f4/3788a1d86e17425eea147e28d7195d7053565fc279236a9fd278c2ec495e/blake3-1.0.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddfc59b0176fb31168f08d5dd536e69b1f4f13b5a0f4b0c3be1003efd47f9308", size = 507536, upload-time = "2025-10-14T06:46:11.614Z" }, - { url = "https://files.pythonhosted.org/packages/fe/01/4639cba48513b94192681b4da472cdec843d3001c5344d7051ee5eaef606/blake3-1.0.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2336d5b2a801a7256da21150348f41610a6c21dae885a3acb1ebbd7333d88d8", size = 394105, upload-time = "2025-10-14T06:46:12.808Z" }, { url = "https://files.pythonhosted.org/packages/21/ae/6e55c19c8460fada86cd1306a390a09b0c5a2e2e424f9317d2edacea439f/blake3-1.0.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4072196547484c95a5a09adbb952e9bb501949f03f9e2a85e7249ef85faaba8", size = 386928, upload-time = "2025-10-14T06:46:16.284Z" }, { url = "https://files.pythonhosted.org/packages/ee/6c/05b7a5a907df1be53a8f19e7828986fc6b608a44119641ef9c0804fbef15/blake3-1.0.8-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0eab3318ec02f8e16fe549244791ace2ada2c259332f0c77ab22cf94dfff7130", size = 550003, upload-time = "2025-10-14T06:46:17.791Z" }, { url = "https://files.pythonhosted.org/packages/b4/03/f0ea4adfedc1717623be6460b3710fcb725ca38082c14274369803f727e1/blake3-1.0.8-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a33b9a1fb6d1d559a8e0d04b041e99419a6bb771311c774f6ff57ed7119c70ed", size = 553857, upload-time = "2025-10-14T06:46:19.088Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6f/e5410d2e2a30c8aba8389ffc1c0061356916bf5ecd0a210344e7b69b62ab/blake3-1.0.8-cp313-cp313-win32.whl", hash = "sha256:e171b169cb7ea618e362a4dddb7a4d4c173bbc08b9ba41ea3086dd1265530d4f", size = 228315, upload-time = "2025-10-14T06:46:20.391Z" }, - { url = "https://files.pythonhosted.org/packages/79/ef/d9c297956dfecd893f29f59e7b22445aba5b47b7f6815d9ba5dcd73fcae6/blake3-1.0.8-cp313-cp313-win_amd64.whl", hash = "sha256:3168c457255b5d2a2fc356ba696996fcaff5d38284f968210d54376312107662", size = 215477, upload-time = "2025-10-14T06:46:21.542Z" }, - { url = "https://files.pythonhosted.org/packages/20/ba/eaa7723d66dd8ab762a3e85e139bb9c46167b751df6e950ad287adb8fb61/blake3-1.0.8-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:b4d672c24dc15ec617d212a338a4ca14b449829b6072d09c96c63b6e6b621aed", size = 347289, upload-time = "2025-10-14T06:46:22.772Z" }, - { url = "https://files.pythonhosted.org/packages/47/b3/6957f6ee27f0d5b8c4efdfda68a1298926a88c099f4dd89c711049d16526/blake3-1.0.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:1af0e5a29aa56d4fba904452ae784740997440afd477a15e583c38338e641f41", size = 324444, upload-time = "2025-10-14T06:46:24.729Z" }, { url = "https://files.pythonhosted.org/packages/13/da/722cebca11238f3b24d3cefd2361c9c9ea47cfa0ad9288eeb4d1e0b7cf93/blake3-1.0.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef153c5860d5bf1cc71aece69b28097d2a392913eb323d6b52555c875d0439fc", size = 370441, upload-time = "2025-10-14T06:46:26.29Z" }, - { url = "https://files.pythonhosted.org/packages/2e/d5/2f7440c8e41c0af995bad3a159e042af0f4ed1994710af5b4766ca918f65/blake3-1.0.8-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e8ae3689f0c7bfa6ce6ae45cab110e4c3442125c4c23b28f1f097856de26e4d1", size = 374312, upload-time = "2025-10-14T06:46:27.451Z" }, - { url = "https://files.pythonhosted.org/packages/a6/6c/fb6a7812e60ce3e110bcbbb11f167caf3e975c589572c41e1271f35f2c41/blake3-1.0.8-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb83532f7456ddeb68dae1b36e1f7c52f9cb72852ac01159bbcb1a12b0f8be0", size = 447007, upload-time = "2025-10-14T06:46:29.056Z" }, - { url = "https://files.pythonhosted.org/packages/13/3b/c99b43fae5047276ea9d944077c190fc1e5f22f57528b9794e21f7adedc6/blake3-1.0.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ae7754c7d96e92a70a52e07c732d594cf9924d780f49fffd3a1e9235e0f5ba7", size = 507323, upload-time = "2025-10-14T06:46:30.661Z" }, - { url = "https://files.pythonhosted.org/packages/fc/bb/ba90eddd592f8c074a0694cb0a744b6bd76bfe67a14c2b490c8bdfca3119/blake3-1.0.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bacaae75e98dee3b7da6c5ee3b81ee21a3352dd2477d6f1d1dbfd38cdbf158a", size = 393449, upload-time = "2025-10-14T06:46:31.805Z" }, { url = "https://files.pythonhosted.org/packages/25/ed/58a2acd0b9e14459cdaef4344db414d4a36e329b9720921b442a454dd443/blake3-1.0.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9456c829601d72852d8ba0af8dae0610f7def1d59f5942efde1e2ef93e8a8b57", size = 386844, upload-time = "2025-10-14T06:46:33.195Z" }, { url = "https://files.pythonhosted.org/packages/4a/04/fed09845b18d90862100c8e48308261e2f663aab25d3c71a6a0bdda6618b/blake3-1.0.8-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:497ef8096ec4ac1ffba9a66152cee3992337cebf8ea434331d8fd9ce5423d227", size = 549550, upload-time = "2025-10-14T06:46:35.23Z" }, { url = "https://files.pythonhosted.org/packages/d6/65/1859fddfabc1cc72548c2269d988819aad96d854e25eae00531517925901/blake3-1.0.8-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:511133bab85ff60ed143424ce484d08c60894ff7323f685d7a6095f43f0c85c3", size = 553805, upload-time = "2025-10-14T06:46:36.532Z" }, - { url = "https://files.pythonhosted.org/packages/c1/c7/2969352017f62378e388bb07bb2191bc9a953f818dc1cd6b9dd5c24916e1/blake3-1.0.8-cp313-cp313t-win32.whl", hash = "sha256:9c9fbdacfdeb68f7ca53bb5a7a5a593ec996eaf21155ad5b08d35e6f97e60877", size = 228068, upload-time = "2025-10-14T06:46:37.826Z" }, - { url = "https://files.pythonhosted.org/packages/d8/fc/923e25ac9cadfff1cd20038bcc0854d0f98061eb6bc78e42c43615f5982d/blake3-1.0.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3cec94ed5676821cf371e9c9d25a41b4f3ebdb5724719b31b2749653b7cc1dfa", size = 215369, upload-time = "2025-10-14T06:46:39.054Z" }, ] [[package]] @@ -632,14 +581,10 @@ version = "6.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/be/db/810437bcfe13cf5e09b68bad1ce57c8fa04ca9272c68946bbf2f4fa522c8/cbor2-6.1.1.tar.gz", hash = "sha256:6f0644869e0fdcd6f3874330b8f1cebd009f33191de43acf609dc2409cd362c4", size = 86297, upload-time = "2026-05-14T10:57:42.231Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/ec/30a52d7f6844cefd37601311a226d091268564a47b0dac56bc0469573681/cbor2-6.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f027e077345ba7d1a88cbed9168196e77f5ce8e8c816305bb1c7a2e4894bddf", size = 409070, upload-time = "2026-05-14T10:57:05.843Z" }, { url = "https://files.pythonhosted.org/packages/b7/a5/653193249a64ca46def52798e8f10ddbc918f11818a977b2aa7248062520/cbor2-6.1.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:559025ad8e1f9f5d019a40dc8f14f43c111c11207b4dde852e943a3002b43ec0", size = 453218, upload-time = "2026-05-14T10:57:07.6Z" }, { url = "https://files.pythonhosted.org/packages/9f/79/bdcb9d43ed537abaa89e662d6340244207ec85b6e66e3bd7f40856c3a5d4/cbor2-6.1.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a6690f7df210386866e120475183132df98f77bf6df624097f66e3214e775084", size = 466244, upload-time = "2026-05-14T10:57:09.297Z" }, { url = "https://files.pythonhosted.org/packages/9c/44/fe0543996d53538c074f8ee18f7391b5458c528b1717740d750a9e472e1d/cbor2-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f4898b5463a567775a05310407dbea5b4a8d7ae8e81337ae9084f5fe226938ff", size = 520804, upload-time = "2026-05-14T10:57:10.682Z" }, { url = "https://files.pythonhosted.org/packages/cd/83/577bbafef3bc887d654a73f3f4ab11e1bd5320abd9108bfc51fbea1498a8/cbor2-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf3ef1fae6f14081a15f178e933ab846d3181f059ee4090975518b71f58bb09f", size = 533598, upload-time = "2026-05-14T10:57:12.098Z" }, - { url = "https://files.pythonhosted.org/packages/57/32/c1c9f435b109ded86ef2e90ff73b95624c84c6edf01489941363a6069725/cbor2-6.1.1-cp313-cp313-win32.whl", hash = "sha256:4642780d27c0b411f4669fcb82e0d7a6b93a0c41c03a0c51296fd6f6858f63fa", size = 281738, upload-time = "2026-05-14T10:57:13.614Z" }, - { url = "https://files.pythonhosted.org/packages/4d/39/9232731f161b2dfe2dc28b06bbacfc2b6a85f1255bf58ebc578ae760ef38/cbor2-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:616bc0538095860fe5607cc06d7b2de3e261a6caccd01ff3f1d4a4a9ad29adbf", size = 300018, upload-time = "2026-05-14T10:57:15.021Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c2/67f2e3a83acfcecad947784bb1590d1978662b5472fcbf7d73e219813456/cbor2-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:7b193d2d024bb5d037e613272f5e436d53f02301101f0ce3916117688643181f", size = 287823, upload-time = "2026-05-14T10:57:16.525Z" }, ] [[package]] @@ -660,18 +605,10 @@ dependencies = [ ] 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/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]] @@ -689,22 +626,10 @@ version = "3.4.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, - { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, - { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, - { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, - { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, - { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, - { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, - { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] @@ -813,28 +738,14 @@ dependencies = [ ] 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/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" }, ] [[package]] @@ -843,36 +754,14 @@ version = "7.14.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/23/7f/d0720730a397a999ffc0fd3f5bebef347338e3a47b727da66fbb228e2ff2/coverage-7.14.0.tar.gz", hash = "sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74", size = 919489, upload-time = "2026-05-10T18:02:31.397Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/76/b7c66ee3c66e1b0f9d894c8125983aa0c03fb2336f2fd16559f9c966157f/coverage-7.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f2bbb8254370eb4c628ff3d6fa8a7f74ddc40565394d4f7ab791d1fe568e37ef", size = 219990, upload-time = "2026-05-10T18:00:38.887Z" }, - { url = "https://files.pythonhosted.org/packages/b3/af/e567cbad5ba69c013a50146dfa886dc7193361fda77521f51274ff620e1b/coverage-7.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23b81107f46d3f21d0cbce30664fcec0f5d9f585638a67081750f99738f6bf66", size = 220365, upload-time = "2026-05-10T18:00:40.864Z" }, - { url = "https://files.pythonhosted.org/packages/44/6f/9ad575d505b4d805b254febc8a5b338a2efe278f8786e56ff1cb8413f9c3/coverage-7.14.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:22a7e06a5f11a757cdfe79018e9095f9f69ae283c5cd8123774c788deec8717b", size = 251363, upload-time = "2026-05-10T18:00:42.489Z" }, { url = "https://files.pythonhosted.org/packages/6f/5f/b5370068b2f57787454592ed7dcd1002f0f1703b7db1fa30f6a325a4ca6e/coverage-7.14.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9d1aa57a1dc8e05bdc42e81c5d671d849577aeedf279f4c449d6d286f9ed88ca", size = 253961, upload-time = "2026-05-10T18:00:44.079Z" }, { url = "https://files.pythonhosted.org/packages/29/1e/51adf17738976e8f2b85ddef7b7aa12a0838b056c92f175941d8862767c1/coverage-7.14.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90c1a51bcfddf645b3bb7ec333d9e94393a8e94f55642380fa8a9a5a9e636cb7", size = 255193, upload-time = "2026-05-10T18:00:45.623Z" }, - { url = "https://files.pythonhosted.org/packages/9e/7b/5bfd7ac1df3b881c2ac7a5cbc99c7609e6296c402f5ef587cd81c6f355b3/coverage-7.14.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a841fae2fadcae4f438d43b6ccc4aac2ad609f47cdb6cfdce60cbb3fe5ca7bc2", size = 257326, upload-time = "2026-05-10T18:00:47.173Z" }, - { url = "https://files.pythonhosted.org/packages/7d/38/1d37d316b174fad3843a1d76dbdfe4398771c9ecd0515935dd9ece9cd627/coverage-7.14.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c79d2319cabef1fe8e86df73371126931550804738f78ad7d31e3aad85a67367", size = 251582, upload-time = "2026-05-10T18:00:49.152Z" }, { url = "https://files.pythonhosted.org/packages/34/46/746704f95980ba220214e1a41e18cec5aea80a898eaa53c51bf2d645ff36/coverage-7.14.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b23b0c6f0b1db6ad769b7050c8b641c0bf215ded26c1816955b17b7f26edfa9", size = 253325, upload-time = "2026-05-10T18:00:51.252Z" }, - { url = "https://files.pythonhosted.org/packages/e1/b9/bbe87206d9687b192352f893797825b5f5b15ecd3aa9c68fbff0c074d77b/coverage-7.14.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:55d3089079ce181a4566b1065ab28d2575eb76d8ac8f81f4fcda2bf037fee087", size = 251291, upload-time = "2026-05-10T18:00:52.816Z" }, - { url = "https://files.pythonhosted.org/packages/46/57/b8cdb12ac0d73ef0243218bd5e22c9df8f92edab8018213a86aec67c5324/coverage-7.14.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:49c005cba1e2f9677fb2845dcdf9a2e72a52a17d63e8231aaaae35d9f50215ef", size = 255448, upload-time = "2026-05-10T18:00:54.548Z" }, - { url = "https://files.pythonhosted.org/packages/1f/d4/5002019538b2036ce3c84340f54d2fd5100d55b0a6b0894eee56128d03c7/coverage-7.14.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9117377b823daa28aa8635fbb08cda1cd6be3d7143257345459559aeef852d52", size = 251110, upload-time = "2026-05-10T18:00:56.122Z" }, { url = "https://files.pythonhosted.org/packages/37/53/20c5009477660f084e6ed60bc02a91894b8e234e617e86ecfd9aaf78e27b/coverage-7.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7b79d646cf46d5cf9a9f40281d4441df5849e445726e369006d2b117710b33fe", size = 252885, upload-time = "2026-05-10T18:00:57.967Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ab/3cf6427ac9c1f1db747dbb1ce71dde47984876d4c2cfd018a3fef0a78d4d/coverage-7.14.0-cp313-cp313-win32.whl", hash = "sha256:fb609b3658479e33f9516d46f1a89dbb9b6c261366e3a11844a96ec487533dae", size = 222539, upload-time = "2026-05-10T18:00:59.581Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b8/9228523e80321c2cb4880d1f589bc0171f2f71432c35118ad04dc01decce/coverage-7.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0773d8329cf32b6fd222e4b52622c61fe8d503eb966cfc8d3c3c10c96266d50e", size = 223344, upload-time = "2026-05-10T18:01:01.531Z" }, - { url = "https://files.pythonhosted.org/packages/a3/99/118daa192f95e3a6cb2740100fbf8797cda1734b4134ef0b5d501a7fa8f3/coverage-7.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:b4e26a0f1b696faf283bffe5b8569e44e336c582439df5d53281ab89ee0cba96", size = 221966, upload-time = "2026-05-10T18:01:03.16Z" }, - { url = "https://files.pythonhosted.org/packages/e6/f1/a46cc0c013be170216253184a32366d7cbdb9252feaec866b05c2d12a894/coverage-7.14.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:953f521ca9445300397e65fda3dca58b2dbd68fee983777420b57ac3c77e9f90", size = 220679, upload-time = "2026-05-10T18:01:05.058Z" }, - { url = "https://files.pythonhosted.org/packages/64/8c/9c30a3d311a34177fa432995be7fbfc64477d8bac5630bd38055b1c9b424/coverage-7.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:98af83fd65ae24b1fdd03aaead967a9f523bcd2f1aab2d4f3ffda65bb568a6f1", size = 221033, upload-time = "2026-05-10T18:01:07.002Z" }, - { url = "https://files.pythonhosted.org/packages/9a/cd/3fb5e06c3badefd0c1b47e2044fdca67f8220a4ec2e7fcfb476aa0a67c6c/coverage-7.14.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:668b92e6958c4db7cf92e81caac328dfbbdbb215db2850ad28f0cbe1eea0bfbd", size = 262333, upload-time = "2026-05-10T18:01:08.903Z" }, { url = "https://files.pythonhosted.org/packages/a8/e6/fbc322325c7294d3e22c1ad6b79e45d0806b25228c8e5842aed6d8169aa7/coverage-7.14.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9fbd898551762dea00d3fef2b1c4f99afd2c6a3ff952ea07d60a9bd5ed4f34bc", size = 264410, upload-time = "2026-05-10T18:01:10.531Z" }, { url = "https://files.pythonhosted.org/packages/08/92/c497b264bec1673c47cc77e26f760fcda4654cabf1f39546d1a23a3b8c35/coverage-7.14.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68af363c07ecd8d4b7d4043d85cb376d7d227eceb54e5323ee45da73dbd3e426", size = 266836, upload-time = "2026-05-10T18:01:12.19Z" }, - { url = "https://files.pythonhosted.org/packages/78/fc/045da320987f401af5d2815d351e8aa799aec859f60e29f445e3089eeedb/coverage-7.14.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e57054a583da8ac55edf24117ea4c9133032cfc4cf72aa2d48c1e5d4b52f899", size = 267974, upload-time = "2026-05-10T18:01:13.926Z" }, - { url = "https://files.pythonhosted.org/packages/1b/ae/227b1e379497fb7a4fc3286e620f80c8a1e7cec66d45695a01639eb1af65/coverage-7.14.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3499459bbcdd51a65b64c35ab7ed2764eaf3cba826e0df3f1d7fe2e102b70b", size = 261578, upload-time = "2026-05-10T18:01:15.564Z" }, { url = "https://files.pythonhosted.org/packages/a0/f5/3570342900f2acea31d33ff1590c5d8bac1a8e1a2e1c6d34a5d5e61de681/coverage-7.14.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:45899ec2138a4346ed34d601dedf5076fb74edf2d1dd9dc76a78e82397edee90", size = 264394, upload-time = "2026-05-10T18:01:17.607Z" }, - { url = "https://files.pythonhosted.org/packages/16/29/de1bbc01c935b28f89b1dc3db85b011c055e843a8e5e3b83141c3f80af7f/coverage-7.14.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8767486808c436f05b23ab98eb963fb29185e32a9357a166971685cb3459900f", size = 262022, upload-time = "2026-05-10T18:01:19.304Z" }, - { url = "https://files.pythonhosted.org/packages/35/95/f53890b0bf2fc10ab168e05d38869215e73ca24c4cb521c3bb0eb62fe16b/coverage-7.14.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a3b5ddfd6aa7ddad53ee3edb231e88a2151507a43229b7d71b953916deca127d", size = 265732, upload-time = "2026-05-10T18:01:21.494Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ea/c919e259081dd2bdf0e43b87209709ba7ec2e4117c2a7f5185379c43463c/coverage-7.14.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:63df0fe568e698e1045792399f8ab6da3a6c2dce3182813fb92afa2641087b47", size = 260921, upload-time = "2026-05-10T18:01:23.533Z" }, { url = "https://files.pythonhosted.org/packages/1a/2c/c2831889705a81dc5d1c6ca12e4d8e9b95dfc146d153488a6c0ea685d28e/coverage-7.14.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:827d6397dbd95144939b18f89edf31f63e1f99633e8d5f32f22ba8bdda567477", size = 263109, upload-time = "2026-05-10T18:01:25.165Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a9/2fcae5003cac3d63fe344d2166243c2756935f48420863c5272b240d550b/coverage-7.14.0-cp313-cp313t-win32.whl", hash = "sha256:7bf43e000d24012599b879791cff41589af90674722421ef11b11a5431920bab", size = 223212, upload-time = "2026-05-10T18:01:27.157Z" }, - { url = "https://files.pythonhosted.org/packages/3f/bb/18e94d7b14b9b398164197114a587a04ab7c9fdbe1d237eef57311c5e883/coverage-7.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3f5549365af25d770e06b1f8f5682d9a5637d06eb494db91c6fa75d3950cc917", size = 224272, upload-time = "2026-05-10T18:01:29.107Z" }, - { url = "https://files.pythonhosted.org/packages/db/56/4f14fad782b035c81c4ffd09159e7103d42bb1d93ac8496d04b90a11b7da/coverage-7.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6d160217ec6fe890f16ad3a9531761589443749e448f91986c972714fad361c8", size = 222530, upload-time = "2026-05-10T18:01:31.151Z" }, { url = "https://files.pythonhosted.org/packages/61/e8/cb8e80d6f9f55b99588625062822bf946cf03ed06315df4bd8397f5632a1/coverage-7.14.0-py3-none-any.whl", hash = "sha256:8de5b61163aee3d05c8a2beab6f47913df7981dad1baf82c414d99158c286ab1", size = 211764, upload-time = "2026-05-10T18:02:29.538Z" }, ] @@ -885,34 +774,22 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" }, { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, - { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, - { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, - { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, - { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" }, - { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" }, { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, - { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, - { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, - { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" }, ] [[package]] @@ -925,10 +802,8 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/36/41ccc303eb6be8ae82c5edd2ccae938876e8a794660e8bb96a193174a978/cuda_bindings-13.0.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb16a7f769c9c67469add7a1d9f6c14dd44637f6921cb6b9eb82cb5015b35c3d", size = 11537064, upload-time = "2025-10-21T15:09:07.84Z" }, { url = "https://files.pythonhosted.org/packages/ab/ac/699889100536f1b63779646291e74eefa818087a0974eb271314d850f5dc/cuda_bindings-13.0.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:512d0d803a5e47a8a42d5a34ce0932802bf72fe952fdb11ac798715a35c6e5cb", size = 11910447, upload-time = "2025-10-21T15:09:09.942Z" }, - { url = "https://files.pythonhosted.org/packages/8c/f9/a2f5910aaf21f4cd43f456ea80f47f1424eece5b8f063dac1980304b8ef0/cuda_bindings-13.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:dd83e8d79587e265b82d3e589ba6b061770537443dfb1bb4a74f755c8b13f62b", size = 11211659, upload-time = "2025-10-21T15:09:12.639Z" }, { url = "https://files.pythonhosted.org/packages/11/67/9656e003f18c5b32e1a2496998b24f4355ec978c5f3639b0eb9f6d0ff83f/cuda_bindings-13.0.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c859e326c776a47e66c50386a10c84fe34291eb6e711610c9fd7cc27d446334f", size = 11522409, upload-time = "2025-10-21T15:09:14.674Z" }, { url = "https://files.pythonhosted.org/packages/18/d8/a83379caa7c1bed4195e704c24467a6c07fe8e29c7055ccd4f00c5702363/cuda_bindings-13.0.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e675dbd009fb5e66d63fd13a8ff35f849120f01bcc4dafadbced3004605c3588", size = 11903148, upload-time = "2025-10-21T15:09:16.918Z" }, - { url = "https://files.pythonhosted.org/packages/7c/e0/ff1eeda06364df8c750843432ac6efb33a06df38261f0a1ceee59bb7dac2/cuda_bindings-13.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:193762306b6032c00a141fc38bcef92c6fb4d332fd2d6a550c7f950e7fd8acd8", size = 11543153, upload-time = "2025-10-21T15:09:19.252Z" }, ] [[package]] @@ -942,7 +817,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/98/ff82ac290e93c771639fd73ba9b37937a97f028169f3e8c121fc258eaca7/cuda_core-0.7.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f25a3042a73dcaa8046a7fa3b0ba9b3de15a39a05b77483dc0a8281bd182716e", size = 29873257, upload-time = "2026-04-08T17:03:26.138Z" }, { url = "https://files.pythonhosted.org/packages/61/21/99169dc3aa66d8fc3eaae7b69fbeaa57a672a71586364069211b7e57e08c/cuda_core-0.7.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52d11f599ec5af622da0b7cf28506978e382aa614f8552edaddbf21bcda6c7a6", size = 30368143, upload-time = "2026-04-08T17:03:29.331Z" }, - { url = "https://files.pythonhosted.org/packages/67/23/0ae61d9e0c78208e97c9b2b274026dead3a46034a3db24ec4568e3cda1d7/cuda_core-0.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:b4dd7c2b2d9f95acbffc9df62bd52d4bcdab72b7780fc3bd7e691e1e0cc1f071", size = 4076762, upload-time = "2026-04-08T17:03:32.059Z" }, ] [[package]] @@ -974,7 +848,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/7d/ee943554f83d6a143d9e0a5cf27cd7f5f8f6ef447c7e8366d9ad6a5d1bf2/cuda_tile-1.3.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:8a9bd4dae193cddf438f55d617b6f25b4b0b0fcf4ac4acde7d2695898e396c30", size = 245750, upload-time = "2026-04-20T15:52:12.91Z" }, { url = "https://files.pythonhosted.org/packages/35/20/e1daea2dc4e094290ba727750f8342095ae857ff3ba4f81c489f48688613/cuda_tile-1.3.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:a44a81e255fdb7bf8e1f7511fe3a019e6045024574509ea8548e0f71f25f8473", size = 247300, upload-time = "2026-04-20T15:51:03.072Z" }, - { url = "https://files.pythonhosted.org/packages/2b/77/c13afad1a06824c1c942afd0205e78ff17f0ee06fc1a943f6e2135cf4112/cuda_tile-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:efcb93c25563fe23d6aa083c22893fd703122eaf684b0d36874982d28a6dad0b", size = 240925, upload-time = "2026-04-20T15:52:21.283Z" }, ] [[package]] @@ -1031,7 +904,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/04/8a/31c58ffa8e1780c8f15492018997d5fb3548427f5fa0e6327becf26f00c6/cupy_cuda13x-14.1.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:42f85f692a589b92a86627113e1072c534cc9d9047433b4291b8bd7b49fb238a", size = 72812202, upload-time = "2026-05-23T01:11:51.015Z" }, { url = "https://files.pythonhosted.org/packages/98/41/be34e911811a0369e3e66b1b618dfccdea1f84ad6a2cc17f146ce9095e99/cupy_cuda13x-14.1.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:eef76f0647af5a9bfe3d0bac641f201deb5f15a644f4b13a2e68c0c62e6808fe", size = 69094718, upload-time = "2026-05-23T01:11:57.103Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c1/c92b4c9c2c561c1298dfad2e3dbb75e527ac1a15d567d8fb868fc277c80e/cupy_cuda13x-14.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:18338008d428bf04dcd73ab2489c6f90c39b7ff439ab2b609115b9bb0e16e0ec", size = 35171775, upload-time = "2026-05-23T01:12:00.57Z" }, ] [[package]] @@ -1049,19 +921,10 @@ version = "3.2.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3f/3b/ebd94c8b85f8e41b5015a9ed94ee3df866024d480d05cd08b774684fb81d/cython-3.2.5.tar.gz", hash = "sha256:3dd42e4cf36ad15f265bdfec2337cc00c688c8eb6d374ffd13bb19437c27bba1", size = 3286381, upload-time = "2026-05-23T19:34:08.439Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/30/f648409de61fd74ae63090071061145059664cc9b9ff8578197601a3beb6/cython-3.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5d7a60835345a8bd29d3aa57070880cc3ce017ea0ade7b9f771ce4bf539b1f", size = 2968935, upload-time = "2026-05-23T19:34:49Z" }, { url = "https://files.pythonhosted.org/packages/4f/1b/95f07b5c0f1996e8e23b30d7aaadf5ecb9fb14d730c48af0963a359fdc25/cython-3.2.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b564f67b01bffa2521f475794b49f2787709cec1f91d5935a38eba37f2b359", size = 3223037, upload-time = "2026-05-23T19:34:51.634Z" }, { url = "https://files.pythonhosted.org/packages/b7/29/ac650cf7eb449619b16d13bc452cac254f3a1843ca0d66dc462993bd4b23/cython-3.2.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0a81220817ff954eddf4512a5b82089094a2f523eb1dc4ad555efd6f07b009b4", size = 3382276, upload-time = "2026-05-23T19:34:53.858Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0f/b3ce218dd833313e9d90c38bdc285f592e50e8e9bb981b49126cd2082141/cython-3.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:3795237ab49753647e329181b140c424e8aa97543074f171f8d2c45e5014a06e", size = 2757027, upload-time = "2026-05-23T19:34:55.803Z" }, - { url = "https://files.pythonhosted.org/packages/a3/de/e3e0cf5704fe569d54b8cd5dc316c9fbf08b1b74728732f86e90168b7a3f/cython-3.2.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:224149d18d980e6ea5001b70fc7ce096c1891d59035dfa9cc5ede50f55804913", size = 2879054, upload-time = "2026-05-23T19:35:18.265Z" }, - { url = "https://files.pythonhosted.org/packages/3c/d1/0a6a8caa35c4c57a1f1866b1141c2d00c6af67f73edbe34b2baec6919ccf/cython-3.2.5-cp39-abi3-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:992a50e90d01813333752f374a4405863113059ec67102ab8d6a431a171ee328", size = 3210422, upload-time = "2026-05-23T19:35:20.641Z" }, - { url = "https://files.pythonhosted.org/packages/07/b8/2523398ec96bb0c9bf69ada625a2256a581940b09fe11fcd0029f26ef4ad/cython-3.2.5-cp39-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8d7b81e6a52a84a02993f01aa5873786ba1dd593c892d93d5fe9866da0bad297", size = 2863809, upload-time = "2026-05-23T19:35:22.416Z" }, { url = "https://files.pythonhosted.org/packages/ff/3d/6b2f316d97bdb02283d79934e50da5cedfec65a536cdd3d69cc3a93486f9/cython-3.2.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:34d21aeb08477c9173e8be7a566b19e880a7c8109ec6bb47a4b20cb680141114", size = 2992518, upload-time = "2026-05-23T19:35:24.737Z" }, - { url = "https://files.pythonhosted.org/packages/68/2c/c9238db1eba208e226d363c00c8b74bf531a6b40c75df2334baa85e142bf/cython-3.2.5-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c4c79e697db55f082a2d3ba97702e71881d5bb1f56f0a80fa338e69101e4c59b", size = 2886221, upload-time = "2026-05-23T19:35:26.64Z" }, - { url = "https://files.pythonhosted.org/packages/2d/15/229cc5c2ed92bb8b43c73a3d31c2b4eaf498409300c34a06d93147f7a42b/cython-3.2.5-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:39acb30eba78ba6d995d5cf3d97d57d450663d93aac6f8b93753d2b89d768c60", size = 3226990, upload-time = "2026-05-23T19:35:28.979Z" }, { url = "https://files.pythonhosted.org/packages/56/31/9c0024f2c772fc303f8cae2a204bcad2fedfaf921ba71cf13a878639432d/cython-3.2.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:382122de8d6b6024fc374fabc3a2b14ba5860ed981c25055ed14fe44278b9dc7", size = 3111004, upload-time = "2026-05-23T19:35:30.957Z" }, - { url = "https://files.pythonhosted.org/packages/82/71/8b528247e42ee63cbe1c1d53805d30b28663fa782c88da4a9b69a1a412dd/cython-3.2.5-cp39-abi3-win32.whl", hash = "sha256:0bc29c7f870b09efdb1f583fbec9592b33af81a7ce273b89c8f5163d7572d5c1", size = 2440395, upload-time = "2026-05-23T19:35:33.082Z" }, - { url = "https://files.pythonhosted.org/packages/50/4d/81c91d3279d156ee2c9ead7ed9eaa862e498066d759e92fb83d0d842c5a7/cython-3.2.5-cp39-abi3-win_arm64.whl", hash = "sha256:85b2944c3eddfc230f9082720195a2e9f869908e5a8b3185be1be832755ee7fc", size = 2446963, upload-time = "2026-05-23T19:35:35.267Z" }, { url = "https://files.pythonhosted.org/packages/d4/5c/9cd909e6a8bb178e4e0f9a2a9227c8201a2be38abe45ada4a4c3e9154277/cython-3.2.5-py3-none-any.whl", hash = "sha256:dc1c8cebb7df5bce37f5f8dc1e5bf04313272a5973d50a55c0ec76c83812911b", size = 1257622, upload-time = "2026-05-23T19:34:05.163Z" }, ] @@ -1238,10 +1101,7 @@ version = "1.8.20" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/e2/fc500524cc6f104a9d049abc85a0a8b3f0d14c0a39b9c140511c61e5b40b/debugpy-1.8.20-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:5dff4bb27027821fdfcc9e8f87309a28988231165147c31730128b1c983e282a", size = 2539560, upload-time = "2026-01-29T23:03:48.738Z" }, { url = "https://files.pythonhosted.org/packages/90/83/fb33dcea789ed6018f8da20c5a9bc9d82adc65c0c990faed43f7c955da46/debugpy-1.8.20-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:84562982dd7cf5ebebfdea667ca20a064e096099997b175fe204e86817f64eaf", size = 4293272, upload-time = "2026-01-29T23:03:50.169Z" }, - { url = "https://files.pythonhosted.org/packages/a6/25/b1e4a01bfb824d79a6af24b99ef291e24189080c93576dfd9b1a2815cd0f/debugpy-1.8.20-cp313-cp313-win32.whl", hash = "sha256:da11dea6447b2cadbf8ce2bec59ecea87cc18d2c574980f643f2d2dfe4862393", size = 5331208, upload-time = "2026-01-29T23:03:51.547Z" }, - { url = "https://files.pythonhosted.org/packages/13/f7/a0b368ce54ffff9e9028c098bd2d28cfc5b54f9f6c186929083d4c60ba58/debugpy-1.8.20-cp313-cp313-win_amd64.whl", hash = "sha256:eb506e45943cab2efb7c6eafdd65b842f3ae779f020c82221f55aca9de135ed7", size = 5372930, upload-time = "2026-01-29T23:03:53.585Z" }, { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, ] @@ -1262,10 +1122,8 @@ dependencies = [ { name = "numpy", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/fb/2d2f27f9fc88b664b3713ed44ef2b8240964903c99def4951d327daeba87/decord2-3.3.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:59e85f8436fc73743057e23b30321afb34818bb82d7c4cec7347f60fb9de2d21", size = 17311167, upload-time = "2026-04-06T18:09:51.709Z" }, { url = "https://files.pythonhosted.org/packages/e8/37/947bc17d6a16f5c678ab2c6ba3330b20f617ec7652f103051881cf1d98d9/decord2-3.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:deadd17cc00b65545ef731fb5f58e05d625dc8db5fbda25edc9bd30469343413", size = 25036754, upload-time = "2026-04-06T18:09:54.204Z" }, { url = "https://files.pythonhosted.org/packages/61/ab/ff85679c25708844a5e1f30e8243dfdb40985b9ce04496dde84a698f4eee/decord2-3.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e8d5408963552843411f2d74aac8025d0bb99c975c48b80e36c989297cf2d145", size = 27392918, upload-time = "2026-04-06T18:09:57.154Z" }, - { url = "https://files.pythonhosted.org/packages/d3/b7/4bc9512474269eda8527d358040ab8a608fe001ab8147c8b238ad4841cc4/decord2-3.3.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:c633a703be369a8bb919f7586f5a39398a7ed7019a8f8ae3931fdff2b87d6a2f", size = 17311166, upload-time = "2026-04-06T18:10:00.088Z" }, { url = "https://files.pythonhosted.org/packages/fe/28/7d116e141a4ec1a3a7ba3ddb7f5e5e7811a23de5468818501ec640a2995b/decord2-3.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:6c7e50d5e3b3471672641cb296bb2616348638e9ce22ecd17bfadc0897907baf", size = 25036756, upload-time = "2026-04-06T18:10:02.647Z" }, { url = "https://files.pythonhosted.org/packages/5e/4c/5cb20dcbb7b62d9453b8d1b18a62f02f8005b402747bbc1d7408bf5a57ce/decord2-3.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3d87266f9a4d211a03e2ce23d64a92e84edbc4364bf36356db47031f9f2ce45e", size = 27392917, upload-time = "2026-04-06T18:10:05.232Z" }, ] @@ -1465,14 +1323,8 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/4c/3d/7ea85d70d85f7d5ed5bf28dc742f106d8334e84286fbc852d983273dd890/dulwich-1.2.6.tar.gz", hash = "sha256:405cfd53a99374ff03aacdd7a86d6a07615feca072ed69721f49ae2ebaa3eab4", size = 1257895, upload-time = "2026-05-31T14:32:52.758Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/ea/f0d0aaf7c9e36f5490579a20ed37c85afd19e90177c2e270ff533d7fd533/dulwich-1.2.6-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:cdd15b8442b527575d733d90cfd6d3c4cbaebf989e2298b0cb57a7916c66254f", size = 1532486, upload-time = "2026-05-31T14:32:18.668Z" }, - { url = "https://files.pythonhosted.org/packages/14/4e/5c212c2dcc2d8c06cafdcdc7893d9516cb861ec277f25a0f058f98512d22/dulwich-1.2.6-cp313-cp313-android_21_x86_64.whl", hash = "sha256:dd2783352917b7cb3ab12b7c3f7757210d93af6df0bd2d876a8e5b53b2feb3eb", size = 1525768, upload-time = "2026-05-31T14:32:20.174Z" }, - { url = "https://files.pythonhosted.org/packages/f4/84/7ff849d4fe769cb6439fc50322381b7eb3d6e5d64da9e5d8337c985a7748/dulwich-1.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:204d14692fb1dd850ab773690f7530f4065f405e9e7dd3f85bdf92e9330ffa2d", size = 1396354, upload-time = "2026-05-31T14:32:21.52Z" }, - { url = "https://files.pythonhosted.org/packages/29/4d/2cb9662dd57417a11e5828f2b8f7607cfaccb42dcd9b6d69316755a5f5e0/dulwich-1.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:21e2e9b81ab04ad83f2d4101ac515ef56ee08d06fd853c1a7ac255f20bb49963", size = 1335031, upload-time = "2026-05-31T14:32:22.978Z" }, { url = "https://files.pythonhosted.org/packages/2e/82/38ccfa7ee30c13d44734c5b1eb92ad0c95a96035319040e2c0b2011eee75/dulwich-1.2.6-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7b4a2f497718bfe1a3b21f933ee27c111b9cea560c0b2d8a6d939e1b5f297f79", size = 1417366, upload-time = "2026-05-31T14:32:24.295Z" }, { url = "https://files.pythonhosted.org/packages/be/a1/239d52cbd94482c064821a0ccece888aac105a81f3f9719b9622c52fe6ec/dulwich-1.2.6-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5ff9f36c95deaf7eb5d6ccde4c68adbcb932a87e03c1b479a8d94d779e7cc5d2", size = 1442588, upload-time = "2026-05-31T14:32:25.731Z" }, - { url = "https://files.pythonhosted.org/packages/6e/92/739dc9e4d5da0b1c09b752f8aad94a518ff5eca7db2f5039ba7d5976b81f/dulwich-1.2.6-cp313-cp313-win32.whl", hash = "sha256:04252b107a1600325f5f0301dde8b5b62f5bb51a0467e360070baddbb4edcea7", size = 1018371, upload-time = "2026-05-31T14:32:27.147Z" }, - { url = "https://files.pythonhosted.org/packages/bb/28/626dc722ab20e0e5d0bf67e212494563f514790bc9c4b7c0133fdf491a5d/dulwich-1.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:6fd9911fb57ee2d6eefaf895df65e1139fbc911fa560e959b38feabe5f15003f", size = 1032986, upload-time = "2026-05-31T14:32:28.66Z" }, { url = "https://files.pythonhosted.org/packages/24/15/61bd455d33979584f19d3a6e0b49b49e0d891bc680fc8cc7b028aea7360d/dulwich-1.2.6-py3-none-any.whl", hash = "sha256:8d8175dbe4feaf62bcafc8708448bfe223b4dfc71609be25c0cf2b0962abc36c", size = 688260, upload-time = "2026-05-31T14:32:51.285Z" }, ] @@ -1632,22 +1484,10 @@ version = "0.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/03/0f/0aeb3fc50046617702acc0078b277b58367fd62eb727b9ec733ae0e8bbcc/fastar-0.11.0.tar.gz", hash = "sha256:aa7f100f7313c03fdb20f1385927ba95671071ba308ad0c1763fef295e1895ce", size = 70238, upload-time = "2026-04-13T17:11:17.143Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/d6/3be260037e86fb694e88d47f583bac3a0188c99cee1a6b257ac26cb6b53c/fastar-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:33f544b08b4541b678e53749b4552a44720d96761fb79c172b005b1089c443ed", size = 707975, upload-time = "2026-04-13T17:09:58.866Z" }, - { url = "https://files.pythonhosted.org/packages/e1/cd/7867aefb1784662554a335f2952c75a50f0c70585ed0d2210d6cc15e5627/fastar-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c1c792447e4a642745f347ff9847c52af39633071c57ee67ed53c157fc3506", size = 628460, upload-time = "2026-04-13T17:09:43.776Z" }, - { url = "https://files.pythonhosted.org/packages/e5/2b/d11d84bdd5e0e377771b955755771e3460b290da5809cb78c1b735ee2228/fastar-0.11.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:881247e6b6eaea59fc6569f9b61447aa6b9fc2ee864e048b4643d69c52745805", size = 863054, upload-time = "2026-04-13T17:09:13.048Z" }, { url = "https://files.pythonhosted.org/packages/25/39/d3f428b318fa940b1b6e785b8d54fc895dfb5d5b945ef8d5442ffa904fb2/fastar-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:863b7929845c9fec92ef6c8d59579cf46af5136655e5342f8df5cebe46cab06c", size = 760247, upload-time = "2026-04-13T17:07:57.396Z" }, - { url = "https://files.pythonhosted.org/packages/9e/04/03949aee82aabb8ede06ac5a4a5579ffaf98a8fe59ce958494508ff15513/fastar-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96b4a57df12bf3211662627a3ea29d62ecb314a2434a0d0843f9fc23e47536e5", size = 756512, upload-time = "2026-04-13T17:08:12.415Z" }, - { url = "https://files.pythonhosted.org/packages/3f/0c/2ca1ae0a3828ca51047962d932b80daca2522db73e8cb9d040cb6ebe28d5/fastar-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceef1c2c4df7b7b8ebd3f5d718bbf457b9bbdf25ce0bd07870211ec4fbd9aff4", size = 922183, upload-time = "2026-04-13T17:08:27.187Z" }, - { url = "https://files.pythonhosted.org/packages/65/68/7fe808b1f73a68e686f25434f538c6dc10ef4dfb3db0ace22cd861744bf8/fastar-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8e545918441910a779659d4759ad0eef349e935fbdb4668a666d3681567eb05", size = 816394, upload-time = "2026-04-13T17:08:57.657Z" }, { url = "https://files.pythonhosted.org/packages/1f/17/07d086080f8a83b8d7966955e29bcdbd6a060f5bd949dc9d5abd3658cead/fastar-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28095bb8f821e85fc2764e1a55f03e5e2876dee2abe7cd0ee9420d929905d643", size = 818983, upload-time = "2026-04-13T17:09:28.46Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e2/2c4edf0910af2e814ff6d65b77a91196d472ca8a9fb2033bd983f6856caa/fastar-0.11.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0fafb95ecbe70f666a5e9b35dd63974ccdc9bb3d99ccdbd4014a823ec3e659b5", size = 884689, upload-time = "2026-04-13T17:08:42.763Z" }, { url = "https://files.pythonhosted.org/packages/fa/ba/04fdcbd6558e60de4ced3b55230fac47675d181252582b2fcec3c74608e5/fastar-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af48fed039b94016629dcdad1c95c90c486326dd068de2b0a4df419ee09b6821", size = 970677, upload-time = "2026-04-13T17:10:15.124Z" }, - { url = "https://files.pythonhosted.org/packages/df/b3/2b860a9658550167dbd5824c85e88d0b4b912bf493e42a6322544d6e483d/fastar-0.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:74cd96163f39b8638ab4e8d49708ca887959672a22871d8170d01f067319533b", size = 1034026, upload-time = "2026-04-13T17:10:32.318Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9b/fa42ea1188b144bac4b1b60753dfd449974a4d5eda132029ee7711569f94/fastar-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e8b993cb5613bab495ed482810bedc0986633fcb9a3b55c37ec88e0d6714f6a", size = 1071147, upload-time = "2026-04-13T17:10:48.833Z" }, { url = "https://files.pythonhosted.org/packages/95/c8/d2e501556dca9f1fbc9246111a31792fb49ad908fa4927f34938a97a3604/fastar-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfe39d91fc28e37e06162d94afe01050220edb7df554acb5b702b5503e564816", size = 1028377, upload-time = "2026-04-13T17:11:06.374Z" }, - { url = "https://files.pythonhosted.org/packages/db/33/5f11f23eca0a569cd052507bc45dda2e5468697f8665728d25be44120f7d/fastar-0.11.0-cp313-cp313-win32.whl", hash = "sha256:c5f63d4d99ff4bfb37c659982ec413358bdee747005348756cc50a04d412d989", size = 454089, upload-time = "2026-04-13T17:11:46.821Z" }, - { url = "https://files.pythonhosted.org/packages/da/2f/35ff03c939cba7a255a9132367873fec6c355fd06a7f84fedcbaf4c8129f/fastar-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8690ed1928d31ded3ada308e1086525fb3871f5fa81e1b69601a3f7774004583", size = 486312, upload-time = "2026-04-13T17:11:32.86Z" }, - { url = "https://files.pythonhosted.org/packages/ef/71/ee9246cbfcbfd4144558f35e7e9a306ffe0a7564730a5188c45f21d2dab8/fastar-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:d977ded9d98a0719a305e0a4d5ee811f1d3e856d853a50acb8ae833c3cd6d5d2", size = 461975, upload-time = "2026-04-13T17:11:22.589Z" }, ] [[package]] @@ -1928,14 +1768,10 @@ version = "4.63.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" }, - { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" }, { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" }, { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" }, { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" }, { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" }, - { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" }, - { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" }, { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, ] @@ -1945,38 +1781,14 @@ 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/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" }, ] @@ -2146,16 +1958,10 @@ version = "3.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3c/3f/dbf99fb14bfeb88c28f16729215478c0e265cacd6dc22270c8f31bb6892f/greenlet-3.5.0.tar.gz", hash = "sha256:d419647372241bc68e957bf38d5c1f98852155e4146bd1e4121adea81f4f01e4", size = 196995, upload-time = "2026-04-27T13:37:15.544Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/58/fc576f99037ce19c5aa16628e4c3226b6d1419f72a62c79f5f40576e6eb3/greenlet-3.5.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5a5ed18de6a0f6cc7087f1563f6bd93fc7df1c19165ca01e9bde5a5dc281d106", size = 285066, upload-time = "2026-04-27T12:23:05.033Z" }, { url = "https://files.pythonhosted.org/packages/4a/ba/b28ddbe6bfad6a8ac196ef0e8cff37bc65b79735995b9e410923fffeeb70/greenlet-3.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a717fbc46d8a354fa675f7c1e813485b6ba3885f9bef0cd56e5ba27d758ff5b", size = 604414, upload-time = "2026-04-27T12:52:42.358Z" }, - { url = "https://files.pythonhosted.org/packages/09/06/4b69f8f0b67603a8be2790e55107a190b376f2627fe0eaf5695d85ffb3cd/greenlet-3.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ddc090c5c1792b10246a78e8c2163ebbe04cf877f9d785c230a7b27b39ad038e", size = 617349, upload-time = "2026-04-27T12:59:43.32Z" }, - { url = "https://files.pythonhosted.org/packages/6a/15/a643b4ecd09969e30b8a150d5919960caae0abe4f5af75ab040b1ab85e78/greenlet-3.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4964101b8585c144cbda5532b1aa644255126c08a265dae90c16e7a0e63aaa9d", size = 623234, upload-time = "2026-04-27T13:02:40.611Z" }, { url = "https://files.pythonhosted.org/packages/8a/17/a3918541fd0ddefe024a69de6d16aa7b46d36ac19562adaa63c7fa180eff/greenlet-3.5.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2094acd54b272cb6eae8c03dd87b3fa1820a4cef18d6889c378d503500a1dc13", size = 613927, upload-time = "2026-04-27T12:25:30.28Z" }, - { url = "https://files.pythonhosted.org/packages/77/18/3b13d5ef1275b0ffaf933b05efa21408ac4ca95823c7411d79682e4fdcff/greenlet-3.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:7022615368890680e67b9965d33f5773aade330d5343bbe25560135aaa849eae", size = 425243, upload-time = "2026-04-27T13:05:15.689Z" }, { url = "https://files.pythonhosted.org/packages/ee/e1/bd0af6213c7dd33175d8a462d4c1fe1175124ebed4855bc1475a5b5242c2/greenlet-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5e05ba267789ea87b5a155cf0e810b1ab88bf18e9e8740813945ceb8ee4350ba", size = 1570893, upload-time = "2026-04-27T12:53:29.483Z" }, { url = "https://files.pythonhosted.org/packages/9b/2a/0789702f864f5382cb476b93d7a9c823c10472658102ccd65f415747d2e2/greenlet-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0ecec963079cd58cbd14723582384f11f166fd58883c15dcbfb342e0bc9b5846", size = 1636060, upload-time = "2026-04-27T12:25:28.845Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8f/22bf9df92bbff0eb07842b60f7e63bf7675a9742df628437a9f02d09137f/greenlet-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:728d9667d8f2f586644b748dbd9bb67e50d6a9381767d1357714ea6825bb3bf5", size = 238740, upload-time = "2026-04-27T12:24:01.341Z" }, - { url = "https://files.pythonhosted.org/packages/b6/b7/9c5c3d653bd4ff614277c049ac676422e2c557db47b4fe43e6313fc005dc/greenlet-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:47422135b1d308c14b2c6e758beedb1acd33bb91679f5670edf77bf46244722b", size = 235525, upload-time = "2026-04-27T12:23:12.308Z" }, ] [[package]] @@ -2167,16 +1973,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" }, - { url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" }, { url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" }, - { url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" }, { url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" }, { url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" }, - { url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" }, { url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" }, - { url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" }, ] [[package]] @@ -2216,16 +2016,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/94/c8/1223f29c84a143ae9a56c084fc96894de0ba84b6e8d60a26241abd81d278/grpcio_tools-1.80.0.tar.gz", hash = "sha256:26052b19c6ce0dcf52d1024496aea3e2bdfa864159f06dc7b97b22d041a94b26", size = 6133212, upload-time = "2026-03-30T08:52:39.077Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/d9/f7887a4805939e9a85d03744b66fc02575dc1df3c3e8b4d9ec000ee7a33d/grpcio_tools-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e7046837859bbfd10b01786056145480155c16b222c9e209215b68d3be13060e", size = 2550319, upload-time = "2026-03-30T08:51:19.117Z" }, - { url = "https://files.pythonhosted.org/packages/57/5a/c8a05b32bd7203f1b9f4c0151090a2d6179d6c97692d32f2066dc29c67a6/grpcio_tools-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a447f28958a8fe84ff0d9d3d9473868feb27ee4a9c9c805e66f5b670121cec59", size = 5709681, upload-time = "2026-03-30T08:51:21.991Z" }, { url = "https://files.pythonhosted.org/packages/82/6b/794350ed645c12c310008f97068f6a6fd927150b0d0d08aad1d909e880b1/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:75f00450e08fe648ad8a1eeb25bc52219679d54cdd02f04dfdddc747309d83f6", size = 2596820, upload-time = "2026-03-30T08:51:24.323Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b2/b39e7b79f7c878135e0784a53cd7260ee77260c8c7f2c9e46bca8e05d017/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3db830eaff1f2c2797328f2fa86c9dcdbd7d81af573a68db81e27afa2182a611", size = 2909193, upload-time = "2026-03-30T08:51:27.025Z" }, { url = "https://files.pythonhosted.org/packages/10/f3/abe089b058f87f9910c9a458409505cbeb0b3e1c2d993a79721d02ee6a32/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7982b5fe42f012686b667dda12916884de95c4b1c65ff64371fb7232a1474b23", size = 2660197, upload-time = "2026-03-30T08:51:29.392Z" }, { url = "https://files.pythonhosted.org/packages/09/c3/3f7806ad8b731d8a89fe3c6ed496473abd1ef4c9c42c9e9a8836ce96e377/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6451b3f4eb52d12c7f32d04bf8e0185f80521f3f088ad04b8d222b3a4819c71e", size = 3113144, upload-time = "2026-03-30T08:51:31.671Z" }, - { url = "https://files.pythonhosted.org/packages/fe/f5/415ef205e0b7e75d2a2005df6120145c4f02fda28d7b3715b55d924fe1a4/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:258bc30654a9a2236be4ca8e2ad443e2ac6db7c8cc20454d34cce60265922726", size = 3661897, upload-time = "2026-03-30T08:51:34.849Z" }, { url = "https://files.pythonhosted.org/packages/e3/d3/2ad54764c2a9547080dd8518f4a4dc7899c7e6e747a1b1de542ce6a12066/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:865a2b8e6334c838976ab02a322cbd55c863d2eaf3c1e1a0255883c63996772a", size = 3328786, upload-time = "2026-03-30T08:51:37.265Z" }, - { url = "https://files.pythonhosted.org/packages/eb/63/23ab7db01f9630ab4f3742a2fc9fbff38b0cfc30c976114f913950664a75/grpcio_tools-1.80.0-cp313-cp313-win32.whl", hash = "sha256:f760ac1722f33e774814c37b6aa0444143f612e85088ead7447a0e9cd306a1f1", size = 997087, upload-time = "2026-03-30T08:51:39.137Z" }, - { url = "https://files.pythonhosted.org/packages/9b/af/b1c1c4423fb49cb7c8e9d2c02196b038c44160b7028b425466743c6c81fa/grpcio_tools-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:7843b9ac6ff8ca508424d0dd968bd9a1a4559967e4a290f26be5bd6f04af2234", size = 1162167, upload-time = "2026-03-30T08:51:41.498Z" }, ] [[package]] @@ -2283,22 +2077,14 @@ version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/74/d8/5c06fc76461418326a7decf8367480c35be11a41fd938633929c60a9ec6b/hf_xet-1.5.0.tar.gz", hash = "sha256:e0fb0a34d9f406eed88233e829a67ec016bec5af19e480eac65a233ea289a948", size = 837196, upload-time = "2026-05-06T06:18:15.583Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/9b/6912c99070915a4f28119e3c5b52a9abd1eec0ad5cb293b8c967a0c6f5a2/hf_xet-1.5.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:7d70fe2ce97b9db73b9c9b9c81fe3693640aec83416a966c446afea54acfae3c", size = 4023383, upload-time = "2026-05-06T06:17:53.947Z" }, - { url = "https://files.pythonhosted.org/packages/0f/6d/9563cfde59b5d8128a9c7ec972a087f4c782e4f7bac5a85234edfd5d5e49/hf_xet-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:73a0dae8c71de3b0633a45c73f4a4a5ed09e94b43441d82981a781d4f12baa42", size = 3792751, upload-time = "2026-05-06T06:17:51.791Z" }, { url = "https://files.pythonhosted.org/packages/07/a5/ed5a0cf35b49a0571af5a8f53416dad1877a718c021c9937c3a53cb45781/hf_xet-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a60290ec57e9b71767fba7c3645ddafdd0759974b540441510c629c6db6db24a", size = 4456058, upload-time = "2026-05-06T06:17:40.735Z" }, { url = "https://files.pythonhosted.org/packages/60/fb/3ae8bf2a7a37a4197d0195d7247fd25b3952e15cb8a599e285dfaa6f52b3/hf_xet-1.5.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e5de0f6deada0dada870bb376a11bcd1f08abf3a968a6d118f33e72d1b1eb480", size = 4250783, upload-time = "2026-05-06T06:17:38.412Z" }, { url = "https://files.pythonhosted.org/packages/a2/9b/8bae40d4d91525085137196e84eb0ed49cf65b5e96e5c3ecdadd8bd0fac2/hf_xet-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c799d49f1a5544a0ef7591c0ee75e0d6b93d6f56dc7a4979f59f7518d2872216", size = 4445594, upload-time = "2026-05-06T06:18:04.219Z" }, { url = "https://files.pythonhosted.org/packages/13/59/c74efbbd4e8728172b2cc72a2bc014d2947a4b7bdced932fbd3f5da1a4e5/hf_xet-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2baea1b0b989e5c152fe81425f7745ddc8901280ba3d97c98d8cdece7b706c60", size = 4663995, upload-time = "2026-05-06T06:18:06.1Z" }, - { url = "https://files.pythonhosted.org/packages/73/32/8e1e0410af64cda9b139d1dcebdc993a8ff9c8c7c0e2696ae356d75ccc0d/hf_xet-1.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:526345b3ed45f374f6317349df489167606736c876241ba984105afe7fd4839d", size = 3966608, upload-time = "2026-05-06T06:18:19.74Z" }, - { url = "https://files.pythonhosted.org/packages/fc/34/a8febc8f4edbea8b3e21b02ebc8b628679b84ba7e45cde624a7736b51500/hf_xet-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:786d28e2eb8315d5035544b9d137b4a842d600c434bb91bf7d0d953cce906ad4", size = 3796946, upload-time = "2026-05-06T06:18:17.568Z" }, - { url = "https://files.pythonhosted.org/packages/3d/fb/69ff198a82cae7eb1a69fb84d93b3a3e4816564d76817fe541ddc96874eb/hf_xet-1.5.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dad0dc84e941b8ba3c860659fe1fdc35c049d47cce293f003287757e971a8f56", size = 4030814, upload-time = "2026-05-06T06:17:57.933Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ff/edcc2b40162bef3ff78e14ab637e5f3b89243d6aee72f5949d3bb6a5af83/hf_xet-1.5.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:fd6e5a9b0fdac4ed03ed45ef79254a655b1aaab514a02202617fbf643f5fdf7a", size = 3798444, upload-time = "2026-05-06T06:17:55.79Z" }, { url = "https://files.pythonhosted.org/packages/49/4d/103f76b04310e5e57656696cc184690d20c466af0bca3ca88f8c8ea5d4f3/hf_xet-1.5.0-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3531b1823a0e6d77d80f9ed15ca0e00f0d115094f8ac033d5cae88f4564cc949", size = 4465986, upload-time = "2026-05-06T06:17:44.886Z" }, { url = "https://files.pythonhosted.org/packages/c4/a2/546f47f464737b3edbab6f8ddb57f2599b93d2cbb66f06abb475ccb48651/hf_xet-1.5.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9a0ee58cd18d5ea799f7ed11290bbccbe56bdd8b1d97ca74b9cc49a3945d7a3b", size = 4259865, upload-time = "2026-05-06T06:17:42.639Z" }, { url = "https://files.pythonhosted.org/packages/95/7f/1be593c1f28613be2e196473481cd81bfc5910795e30a34e8f744f6cac4f/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e60df5a42e9bed8628b6416af2cba4cba57ae9f02de226a06b020d98e1aab18", size = 4459835, upload-time = "2026-05-06T06:18:08.026Z" }, { url = "https://files.pythonhosted.org/packages/aa/b2/703569fc881f3284487e68cda7b42179978480da3c438042a6bbbb4a671c/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4b35549ce62601b84da4ff9b24d970032ace3d4430f52d91bcbb26c901d6c690", size = 4672414, upload-time = "2026-05-06T06:18:09.864Z" }, - { url = "https://files.pythonhosted.org/packages/af/37/1b6def445c567286b50aa3b33828158e135b1be44938dde59f11382a500c/hf_xet-1.5.0-cp37-abi3-win_amd64.whl", hash = "sha256:2806c7c17b4d23f8d88f7c4814f838c3b6150773fe339c20af23e1cfaf2797e4", size = 3977238, upload-time = "2026-05-06T06:18:23.621Z" }, - { url = "https://files.pythonhosted.org/packages/62/94/3b66b148778ee100dcfd69c2ca22b57b41b44d3063ceec934f209e9184ce/hf_xet-1.5.0-cp37-abi3-win_arm64.whl", hash = "sha256:b6c9df403040248c76d808d3e047d64db2d923bae593eb244c41e425cf6cd7be", size = 3806916, upload-time = "2026-05-06T06:18:21.7Z" }, ] [[package]] @@ -2329,13 +2115,10 @@ 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/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]] @@ -2468,28 +2251,14 @@ version = "3.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f4/57/60d1a6a512f2f0508d0bc8b4f1cc5616fd3196619b66bd6a01f9155a1292/ijson-3.5.0.tar.gz", hash = "sha256:94688760720e3f5212731b3cb8d30267f9a045fb38fb3870254e7b9504246f31", size = 68658, upload-time = "2026-02-24T03:58:30.974Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/71/d67e764a712c3590627480643a3b51efcc3afa4ef3cb54ee4c989073c97e/ijson-3.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e9cedc10e40dd6023c351ed8bfc7dcfce58204f15c321c3c1546b9c7b12562a4", size = 88544, upload-time = "2026-02-24T03:57:21.293Z" }, - { url = "https://files.pythonhosted.org/packages/1a/39/f1c299371686153fa3cf5c0736b96247a87a1bee1b7145e6d21f359c505a/ijson-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3647649f782ee06c97490b43680371186651f3f69bebe64c6083ee7615d185e5", size = 60495, upload-time = "2026-02-24T03:57:22.501Z" }, - { url = "https://files.pythonhosted.org/packages/16/94/b1438e204d75e01541bebe3e668fe3e68612d210e9931ae1611062dd0a56/ijson-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90e74be1dce05fce73451c62d1118671f78f47c9f6be3991c82b91063bf01fc9", size = 60325, upload-time = "2026-02-24T03:57:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/30/e2/4aa9c116fa86cc8b0f574f3c3a47409edc1cd4face05d0e589a5a176b05d/ijson-3.5.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:78e9ad73e7be2dd80627504bd5cbf512348c55ce2c06e362ed7683b5220e8568", size = 138774, upload-time = "2026-02-24T03:57:24.683Z" }, { url = "https://files.pythonhosted.org/packages/d2/d2/738b88752a70c3be1505faa4dcd7110668c2712e582a6a36488ed1e295d4/ijson-3.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9577449313cc94be89a4fe4b3e716c65f09cc19636d5a6b2861c4e80dddebd58", size = 149820, upload-time = "2026-02-24T03:57:26.062Z" }, { url = "https://files.pythonhosted.org/packages/ed/df/0b3ab9f393ca8f72ea03bc896ba9fdc987e90ae08cdb51c32a4ee0c14d5e/ijson-3.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e4c1178fb50aff5f5701a30a5152ead82a14e189ce0f6102fa1b5f10b2f54ff", size = 149747, upload-time = "2026-02-24T03:57:27.308Z" }, { url = "https://files.pythonhosted.org/packages/cc/a3/b0037119f75131b78cb00acc2657b1a9d0435475f1f2c5f8f5a170b66b9c/ijson-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0eb402ab026ffb37a918d75af2b7260fe6cfbce13232cc83728a714dd30bd81d", size = 151027, upload-time = "2026-02-24T03:57:28.522Z" }, - { url = "https://files.pythonhosted.org/packages/22/a0/cb344de1862bf09d8f769c9d25c944078c87dd59a1b496feec5ad96309a4/ijson-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5b08ee08355f9f729612a8eb9bf69cc14f9310c3b2a487c6f1c3c65d85216ec4", size = 142996, upload-time = "2026-02-24T03:57:29.774Z" }, { url = "https://files.pythonhosted.org/packages/ca/32/a8ffd67182e02ea61f70f62daf43ded4fa8a830a2520a851d2782460aba8/ijson-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bda62b6d48442903e7bf56152108afb7f0f1293c2b9bef2f2c369defea76ab18", size = 152068, upload-time = "2026-02-24T03:57:30.969Z" }, - { url = "https://files.pythonhosted.org/packages/3c/d1/3578df8e75d446aab0ae92e27f641341f586b85e1988536adebc65300cb4/ijson-3.5.0-cp313-cp313-win32.whl", hash = "sha256:8d073d9b13574cfa11083cc7267c238b7a6ed563c2661e79192da4a25f09c82c", size = 53065, upload-time = "2026-02-24T03:57:31.93Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a2/f7cdaf5896710da3e69e982e44f015a83d168aa0f3a89b6f074b5426779d/ijson-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:2419f9e32e0968a876b04d8f26aeac042abd16f582810b576936bbc4c6015069", size = 55499, upload-time = "2026-02-24T03:57:32.773Z" }, - { url = "https://files.pythonhosted.org/packages/42/65/13e2492d17e19a2084523e18716dc2809159f2287fd2700c735f311e76c4/ijson-3.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4d4b0cd676b8c842f7648c1a783448fac5cd3b98289abd83711b3e275e143524", size = 93019, upload-time = "2026-02-24T03:57:33.976Z" }, - { url = "https://files.pythonhosted.org/packages/33/92/483fc97ece0c3f1cecabf48f6a7a36e89d19369eec462faaeaa34c788992/ijson-3.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:252dec3680a48bb82d475e36b4ae1b3a9d7eb690b951bb98a76c5fe519e30188", size = 62714, upload-time = "2026-02-24T03:57:34.819Z" }, - { url = "https://files.pythonhosted.org/packages/4b/88/793fe020a0fe9d9eed4c285cf4a5cfdb0a935708b3bde0d72f35c794b513/ijson-3.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:aa1b5dca97d323931fde2501172337384c958914d81a9dac7f00f0d4bfc76bc7", size = 62460, upload-time = "2026-02-24T03:57:35.874Z" }, - { url = "https://files.pythonhosted.org/packages/51/69/f1a2690aa8d4df1f4e262b385e65a933ffdc250b091531bac9a449c19e16/ijson-3.5.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7a5ec7fd86d606094bba6f6f8f87494897102fa4584ef653f3005c51a784c320", size = 199273, upload-time = "2026-02-24T03:57:37.07Z" }, { url = "https://files.pythonhosted.org/packages/ea/a2/f1346d5299e79b988ab472dc773d5381ec2d57c23cb2f1af3ede4a810e62/ijson-3.5.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:009f41443e1521847701c6d87fa3923c0b1961be3c7e7de90947c8cb92ea7c44", size = 216884, upload-time = "2026-02-24T03:57:38.346Z" }, { url = "https://files.pythonhosted.org/packages/28/3c/8b637e869be87799e6c2c3c275a30a546f086b1aed77e2b7f11512168c5a/ijson-3.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e4c3651d1f9fe2839a93fdf8fd1d5ca3a54975349894249f3b1b572bcc4bd577", size = 207306, upload-time = "2026-02-24T03:57:39.718Z" }, { url = "https://files.pythonhosted.org/packages/7f/7c/18b1c1df6951ca056782d7580ec40cea4ff9a27a0947d92640d1cc8c4ae3/ijson-3.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:945b7abcfcfeae2cde17d8d900870f03536494245dda7ad4f8d056faa303256c", size = 211364, upload-time = "2026-02-24T03:57:40.953Z" }, - { url = "https://files.pythonhosted.org/packages/f3/55/e795812e82851574a9dba8a53fde045378f531ef14110c6fb55dbd23b443/ijson-3.5.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0574b0a841ff97495c13e9d7260fbf3d85358b061f540c52a123db9dbbaa2ed6", size = 200608, upload-time = "2026-02-24T03:57:42.272Z" }, { url = "https://files.pythonhosted.org/packages/5c/cd/013c85b4749b57a4cb4c2670014d1b32b8db4ab1a7be92ea7aeb5d7fe7b5/ijson-3.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f969ffb2b89c5cdf686652d7fb66252bc72126fa54d416317411497276056a18", size = 205127, upload-time = "2026-02-24T03:57:43.286Z" }, - { url = "https://files.pythonhosted.org/packages/0e/7c/faf643733e3ab677f180018f6a855c4ef70b7c46540987424c563c959e42/ijson-3.5.0-cp313-cp313t-win32.whl", hash = "sha256:59d3f9f46deed1332ad669518b8099920512a78bda64c1f021fcd2aff2b36693", size = 55282, upload-time = "2026-02-24T03:57:44.353Z" }, - { url = "https://files.pythonhosted.org/packages/69/22/94ddb47c24b491377aca06cd8fc9202cad6ab50619842457d2beefde21ea/ijson-3.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c2839fa233746d8aad3b8cd2354e441613f5df66d721d59da4a09394bd1db2b", size = 58016, upload-time = "2026-02-24T03:57:45.237Z" }, ] [[package]] @@ -2603,25 +2372,12 @@ version = "0.14.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6e/c1/0cddc6eb17d4c53a99840953f95dd3accdc5cfc7a337b0e9b26476276be9/jiter-0.14.0.tar.gz", hash = "sha256:e8a39e66dac7153cf3f964a12aad515afa8d74938ec5cc0018adcdae5367c79e", size = 165725, upload-time = "2026-04-10T14:28:42.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/2a/09f70020898507a89279659a1afe3364d57fc1b2c89949081975d135f6f5/jiter-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:af72f204cf4d44258e5b4c1745130ac45ddab0e71a06333b01de660ab4187a94", size = 315502, upload-time = "2026-04-10T14:26:47.697Z" }, - { url = "https://files.pythonhosted.org/packages/d6/be/080c96a45cd74f9fce5db4fd68510b88087fb37ffe2541ff73c12db92535/jiter-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4b77da71f6e819be5fbcec11a453fde5b1d0267ef6ed487e2a392fd8e14e4e3a", size = 314870, upload-time = "2026-04-10T14:26:49.149Z" }, { url = "https://files.pythonhosted.org/packages/7d/5e/2d0fee155826a968a832cc32438de5e2a193292c8721ca70d0b53e58245b/jiter-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f4ea612fe8b84b8b04e51d0e78029ecf3466348e25973f953de6e6a59aa4c1", size = 343406, upload-time = "2026-04-10T14:26:50.762Z" }, - { url = "https://files.pythonhosted.org/packages/70/af/bf9ee0d3a4f8dc0d679fc1337f874fe60cdbf841ebbb304b374e1c9aaceb/jiter-0.14.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62fe2451f8fcc0240261e6a4df18ecbcd58327857e61e625b2393ea3b468aac9", size = 369415, upload-time = "2026-04-10T14:26:52.188Z" }, - { url = "https://files.pythonhosted.org/packages/0f/83/8e8561eadba31f4d3948a5b712fb0447ec71c3560b57a855449e7b8ddc98/jiter-0.14.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6112f26f5afc75bcb475787d29da3aa92f9d09c7858f632f4be6ffe607be82e9", size = 461456, upload-time = "2026-04-10T14:26:53.611Z" }, - { url = "https://files.pythonhosted.org/packages/f6/c9/c5299e826a5fe6108d172b344033f61c69b1bb979dd8d9ddd4278a160971/jiter-0.14.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:215a6cb8fb7dc702aa35d475cc00ddc7f970e5c0b1417fb4b4ac5d82fa2a29db", size = 378488, upload-time = "2026-04-10T14:26:55.211Z" }, { url = "https://files.pythonhosted.org/packages/5d/37/c16d9d15c0a471b8644b1abe3c82668092a707d9bedcf076f24ff2e380cd/jiter-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ab96a30fb3cb2c7e0cd33f7616c8860da5f5674438988a54ac717caccdbaa", size = 353242, upload-time = "2026-04-10T14:26:56.705Z" }, - { url = "https://files.pythonhosted.org/packages/58/ea/8050cb0dc654e728e1bfacbc0c640772f2181af5dedd13ae70145743a439/jiter-0.14.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:3a99c1387b1f2928f799a9de899193484d66206a50e98233b6b088a7f0c1edb2", size = 356823, upload-time = "2026-04-10T14:26:58.281Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3b/cf71506d270e5f84d97326bf220e47aed9b95e9a4a060758fb07772170ab/jiter-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ab18d11074485438695f8d34a1b6da61db9754248f96d51341956607a8f39985", size = 392564, upload-time = "2026-04-10T14:27:00.018Z" }, { url = "https://files.pythonhosted.org/packages/b0/cc/8c6c74a3efb5bd671bfd14f51e8a73375464ca914b1551bc3b40e26ac2c9/jiter-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:801028dcfc26ac0895e4964cbc0fd62c73be9fd4a7d7b1aaf6e5790033a719b7", size = 520322, upload-time = "2026-04-10T14:27:01.664Z" }, { url = "https://files.pythonhosted.org/packages/41/24/68d7b883ec959884ddf00d019b2e0e82ba81b167e1253684fa90519ce33c/jiter-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ad425b087aafb4a1c7e1e98a279200743b9aaf30c3e0ba723aec93f061bd9bc8", size = 552619, upload-time = "2026-04-10T14:27:03.316Z" }, - { url = "https://files.pythonhosted.org/packages/b6/89/b1a0985223bbf3150ff9e8f46f98fc9360c1de94f48abe271bbe1b465682/jiter-0.14.0-cp313-cp313-win32.whl", hash = "sha256:882bcb9b334318e233950b8be366fe5f92c86b66a7e449e76975dfd6d776a01f", size = 205699, upload-time = "2026-04-10T14:27:04.662Z" }, - { url = "https://files.pythonhosted.org/packages/4c/19/3f339a5a7f14a11730e67f6be34f9d5105751d547b615ef593fa122a5ded/jiter-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:9b8c571a5dba09b98bd3462b5a53f27209a5cbbe85670391692ede71974e979f", size = 201323, upload-time = "2026-04-10T14:27:06.139Z" }, - { url = "https://files.pythonhosted.org/packages/50/56/752dd89c84be0e022a8ea3720bcfa0a8431db79a962578544812ce061739/jiter-0.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:34f19dcc35cb1abe7c369b3756babf8c7f04595c0807a848df8f26ef8298ef92", size = 191099, upload-time = "2026-04-10T14:27:07.564Z" }, - { url = "https://files.pythonhosted.org/packages/91/28/292916f354f25a1fe8cf2c918d1415c699a4a659ae00be0430e1c5d9ffea/jiter-0.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e89bcd7d426a75bb4952c696b267075790d854a07aad4c9894551a82c5b574ab", size = 320880, upload-time = "2026-04-10T14:27:09.326Z" }, { url = "https://files.pythonhosted.org/packages/ad/c7/b002a7d8b8957ac3d469bd59c18ef4b1595a5216ae0de639a287b9816023/jiter-0.14.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b25beaa0d4447ea8c7ae0c18c688905d34840d7d0b937f2f7bdd52162c98a40", size = 346563, upload-time = "2026-04-10T14:27:11.287Z" }, { url = "https://files.pythonhosted.org/packages/f9/3b/f8d07580d8706021d255a6356b8fab13ee4c869412995550ce6ed4ddf97d/jiter-0.14.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a8758dd413c51e3b7f6557cdc6921faf70b14106f45f969f091f5cda990ea", size = 357928, upload-time = "2026-04-10T14:27:12.729Z" }, - { url = "https://files.pythonhosted.org/packages/47/5b/ac1a974da29e35507230383110ffec59998b290a8732585d04e19a9eb5ba/jiter-0.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e1a7eead856a5038a8d291f1447176ab0b525c77a279a058121b5fccee257f6f", size = 203519, upload-time = "2026-04-10T14:27:14.125Z" }, - { url = "https://files.pythonhosted.org/packages/96/6d/9fc8433d667d2454271378a79747d8c76c10b51b482b454e6190e511f244/jiter-0.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e692633a12cda97e352fdcd1c4acc971b1c28707e1e33aeef782b0cbf051975", size = 190113, upload-time = "2026-04-10T14:27:16.638Z" }, ] [[package]] @@ -2698,35 +2454,14 @@ version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, - { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, - { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, - { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, - { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, - { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, - { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, - { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, - { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, - { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, - { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, - { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, - { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, - { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, - { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, - { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, - { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, ] [[package]] @@ -2757,19 +2492,10 @@ version = "0.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" }, - { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" }, { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" }, { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" }, - { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" }, { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" }, - { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" }, - { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" }, { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" }, - { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" }, - { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" }, ] [[package]] @@ -2778,13 +2504,8 @@ version = "1.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/95/48/3f7a9d3ff1b36bba92b5107a3a21286821227afe9ea464736133994d61fb/llguidance-1.3.0.tar.gz", hash = "sha256:861249afd51dc325646834462ea827e57a5c2b2042e108e6aae7059fdad9104d", size = 1070460, upload-time = "2025-10-20T19:58:44.164Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/33/be5acb85cd8cdc4afde33d9c234eece9f318e087920255af3c05864cd3e7/llguidance-1.3.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f7685222660a762e481ac633d49cc559c64980fe2ee59c8f932a5bb5cbc0c2c2", size = 3220647, upload-time = "2025-10-20T19:58:42.542Z" }, - { url = "https://files.pythonhosted.org/packages/82/e6/b48bda5b15efeaeb62bd0dba8fc6a01d4ae5457a85dbb5d18632385fe15c/llguidance-1.3.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:098030ff0687261a3f1bd54cf21fe951fc861d56d37a0671250dd36677eaf224", size = 3099830, upload-time = "2025-10-20T19:58:40.826Z" }, { url = "https://files.pythonhosted.org/packages/aa/11/44389d3d1526d7a5c38ffd587a5ebc61d7bee443ac1dea95f2089ad58f5f/llguidance-1.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f6caca5d78db7f76e1fbb0fff8607b861c32d47fa3d5dee2fc49de27ee269df", size = 2835242, upload-time = "2025-10-20T19:58:34.518Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ca/53ea256396405e4dee70d5a4a35e18543408e18bb16b251d6ca6b5d80310/llguidance-1.3.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0612bb3f034d2487b6e8f9561f02a94a6039d88273bf0c5c539a3bd3895e47d2", size = 3297480, upload-time = "2025-10-20T19:58:37.033Z" }, { url = "https://files.pythonhosted.org/packages/83/a8/1ff2bedb8f9acb46a2d2d603415d272bb622c142ea86f5b95445cc6e366c/llguidance-1.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc17e9dd602c3879bf91664a64bf72f54c74dbfbeb24ccfab6a5fe435b12f7aa", size = 3033133, upload-time = "2025-10-20T19:58:38.721Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a7/9b8086c0cfdddf3f6d47b173a404fa7ac46272f7affbee082c36740f4f1c/llguidance-1.3.0-cp39-abi3-win32.whl", hash = "sha256:2f6f558485a43e273fc5c6c974a9a3ace5d5e170076db9b40e0560e41c3ff18f", size = 2598109, upload-time = "2025-10-20T19:58:47.656Z" }, - { url = "https://files.pythonhosted.org/packages/5a/7e/809349638231f469b9056c0e1bfd924d5ef5558b3b3ec72d093b6fad33b1/llguidance-1.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:1d1cd1c8618d1a13605d3e057c978651e551c8c469b481ee4041f1d6c436002d", size = 2789946, upload-time = "2025-10-20T19:58:45.958Z" }, ] [[package]] @@ -2793,10 +2514,8 @@ version = "0.47.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz", hash = "sha256:62031ce968ec74e95092184d4b0e857e444f8fdff0b8f9213707699570c33ccc", size = 193614, upload-time = "2026-03-31T18:29:53.497Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/6f/4615353e016799f80fa52ccb270a843c413b22361fadda2589b2922fb9b0/llvmlite-0.47.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a3c6a735d4e1041808434f9d440faa3d78d9b4af2ee64d05a66f351883b6ceec", size = 37232771, upload-time = "2026-03-31T18:29:01.324Z" }, { url = "https://files.pythonhosted.org/packages/31/b8/69f5565f1a280d032525878a86511eebed0645818492feeb169dfb20ae8e/llvmlite-0.47.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2699a74321189e812d476a43d6d7f652f51811e7b5aad9d9bba842a1c7927acb", size = 56275178, upload-time = "2026-03-31T18:29:05.748Z" }, { url = "https://files.pythonhosted.org/packages/d6/da/b32cafcb926fb0ce2aa25553bf32cb8764af31438f40e2481df08884c947/llvmlite-0.47.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c6951e2b29930227963e53ee152441f0e14be92e9d4231852102d986c761e40", size = 55128632, upload-time = "2026-03-31T18:29:11.235Z" }, - { url = "https://files.pythonhosted.org/packages/46/9f/4898b44e4042c60fafcb1162dfb7014f6f15b1ec19bf29cfea6bf26df90d/llvmlite-0.47.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2e9adf8698d813a9a5efb2d4370caf344dbc1e145019851fee6a6f319ba760e", size = 38138695, upload-time = "2026-03-31T18:29:15.43Z" }, ] [[package]] @@ -2829,24 +2548,12 @@ version = "6.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/28/30/9abc9e34c657c33834eaf6cd02124c61bdf5944d802aa48e69be8da3585d/lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", size = 4197006, upload-time = "2026-04-18T04:32:51.613Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/03/69347590f1cf4a6d5a4944bb6099e6d37f334784f16062234e1f892fdb1d/lxml-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45", size = 8559689, upload-time = "2026-04-18T04:31:57.785Z" }, - { url = "https://files.pythonhosted.org/packages/3f/58/25e00bb40b185c974cfe156c110474d9a8a8390d5f7c92a4e328189bb60e/lxml-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d", size = 4617892, upload-time = "2026-04-18T04:32:01.78Z" }, { url = "https://files.pythonhosted.org/packages/f5/54/92ad98a94ac318dc4f97aaac22ff8d1b94212b2ae8af5b6e9b354bf825f7/lxml-6.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2", size = 4923489, upload-time = "2026-04-18T04:33:31.401Z" }, { url = "https://files.pythonhosted.org/packages/15/3b/a20aecfab42bdf4f9b390590d345857ad3ffd7c51988d1c89c53a0c73faf/lxml-6.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491", size = 5082162, upload-time = "2026-04-18T04:33:34.262Z" }, { url = "https://files.pythonhosted.org/packages/45/26/2cdb3d281ac1bd175603e290cbe4bad6eff127c0f8de90bafd6f8548f0fd/lxml-6.1.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc", size = 4993247, upload-time = "2026-04-18T04:33:36.674Z" }, - { url = "https://files.pythonhosted.org/packages/f6/05/d735aef963740022a08185c84821f689fc903acb3d50326e6b1e9886cc22/lxml-6.1.0-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e", size = 5613042, upload-time = "2026-04-18T04:33:39.205Z" }, { url = "https://files.pythonhosted.org/packages/ee/b8/ead7c10efff731738c72e59ed6eb5791854879fbed7ae98781a12006263a/lxml-6.1.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2", size = 5228304, upload-time = "2026-04-18T04:33:41.647Z" }, - { url = "https://files.pythonhosted.org/packages/6b/10/e9842d2ec322ea65f0a7270aa0315a53abed06058b88ef1b027f620e7a5f/lxml-6.1.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9", size = 5341578, upload-time = "2026-04-18T04:33:44.596Z" }, - { url = "https://files.pythonhosted.org/packages/89/54/40d9403d7c2775fa7301d3ddd3464689bfe9ba71acc17dfff777071b4fdc/lxml-6.1.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe", size = 4700209, upload-time = "2026-04-18T04:33:47.552Z" }, - { url = "https://files.pythonhosted.org/packages/85/b2/bbdcc2cf45dfc7dfffef4fd97e5c47b15919b6a365247d95d6f684ef5e82/lxml-6.1.0-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88", size = 5232365, upload-time = "2026-04-18T04:33:50.249Z" }, { url = "https://files.pythonhosted.org/packages/48/5a/b06875665e53aaba7127611a7bed3b7b9658e20b22bc2dd217a0b7ab0091/lxml-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181", size = 5043654, upload-time = "2026-04-18T04:33:52.71Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9c/e71a069d09641c1a7abeb30e693f828c7c90a41cbe3d650b2d734d876f85/lxml-6.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24", size = 4769326, upload-time = "2026-04-18T04:33:55.244Z" }, - { url = "https://files.pythonhosted.org/packages/cc/06/7a9cd84b3d4ed79adf35f874750abb697dec0b4a81a836037b36e47c091a/lxml-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e", size = 5635879, upload-time = "2026-04-18T04:33:58.509Z" }, - { url = "https://files.pythonhosted.org/packages/cc/f0/9d57916befc1e54c451712c7ee48e9e74e80ae4d03bdce49914e0aee42cd/lxml-6.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495", size = 5224048, upload-time = "2026-04-18T04:34:00.943Z" }, { url = "https://files.pythonhosted.org/packages/99/75/90c4eefda0c08c92221fe0753db2d6699a4c628f76ff4465ec20dea84cc1/lxml-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33", size = 5250241, upload-time = "2026-04-18T04:34:03.365Z" }, - { url = "https://files.pythonhosted.org/packages/5e/73/16596f7e4e38fa33084b9ccbccc22a15f82a290a055126f2c1541236d2ff/lxml-6.1.0-cp313-cp313-win32.whl", hash = "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62", size = 3596938, upload-time = "2026-04-18T04:31:56.206Z" }, - { url = "https://files.pythonhosted.org/packages/8e/63/981401c5680c1eb30893f00a19641ac80db5d1e7086c62cb4b13ed813038/lxml-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16", size = 3995728, upload-time = "2026-04-18T04:31:58.763Z" }, - { url = "https://files.pythonhosted.org/packages/e7/e8/c358a38ac3e541d16a1b527e4e9cb78c0419b0506a070ace11777e5e8404/lxml-6.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d", size = 3658372, upload-time = "2026-04-18T04:32:03.629Z" }, ] [[package]] @@ -2899,28 +2606,14 @@ 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/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]] @@ -2952,20 +2645,12 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/d3/8d4f6afbecb49fc04e060a57c0fce39ea51cc163a6bd87303ccd698e4fa6/matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f", size = 8320331, upload-time = "2026-04-24T00:12:39.688Z" }, - { url = "https://files.pythonhosted.org/packages/63/d9/9e14bc7564bf92d5ffa801ae5fac819ce74b925dfb55e3ebde61a3bbad3e/matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e", size = 8216461, upload-time = "2026-04-24T00:12:42.494Z" }, { url = "https://files.pythonhosted.org/packages/8a/17/4402d0d14ccf1dfc70932600b68097fbbf9c898a4871d2cbbe79c7801a32/matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f", size = 8790091, upload-time = "2026-04-24T00:12:44.789Z" }, { url = "https://files.pythonhosted.org/packages/3e/0b/322aeec06dd9b91411f92028b37d447342770a24392aa4813e317064dad5/matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838", size = 9605027, upload-time = "2026-04-24T00:12:47.583Z" }, { url = "https://files.pythonhosted.org/packages/74/88/5f13482f55e7b00bcfc09838b093c2456e1379978d2a146844aae05350ad/matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2", size = 9671269, upload-time = "2026-04-24T00:12:50.878Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e0/0840fd2f93da988ec660b8ad1984abe9f25d2aed22a5e394ff1c68c88307/matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921", size = 8217588, upload-time = "2026-04-24T00:12:53.784Z" }, - { url = "https://files.pythonhosted.org/packages/47/b9/d706d06dd605c49b9f83a2aed8c13e3e5db70697d7a80b7e3d7915de6b17/matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8", size = 8136913, upload-time = "2026-04-24T00:12:56.501Z" }, - { url = "https://files.pythonhosted.org/packages/9b/45/6e32d96978264c8ca8c4b1010adb955a1a49cfaf314e212bbc8908f04a61/matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9", size = 8368019, upload-time = "2026-04-24T00:12:58.896Z" }, - { url = "https://files.pythonhosted.org/packages/86/0a/c8e3d3bba245f0f7fc424937f8ff7ef77291a36af3edb97ccd78aa93d84f/matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4", size = 8264645, upload-time = "2026-04-24T00:13:01.406Z" }, { url = "https://files.pythonhosted.org/packages/3d/aa/5bf5a14fe4fed73a4209a155606f8096ff797aad89c6c35179026571133e/matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc", size = 8802194, upload-time = "2026-04-24T00:13:03.702Z" }, { url = "https://files.pythonhosted.org/packages/dd/5e/b4be852d6bba6fd15893fadf91ff26ae49cb91aac789e95dde9d342e664f/matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99", size = 9622684, upload-time = "2026-04-24T00:13:06.647Z" }, { url = "https://files.pythonhosted.org/packages/4c/3d/ed428c971139112ef730f62770654d609467346d09d4b62617e1afd68a5a/matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d", size = 9680790, upload-time = "2026-04-24T00:13:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/e7/09/052e884aaf2b985c63cb79f715f1d5b6a3eaa7de78f6a52b9dbc077d5b53/matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8", size = 8287571, upload-time = "2026-04-24T00:13:13.087Z" }, - { url = "https://files.pythonhosted.org/packages/f4/38/ae27288e788c35a4250491422f3db7750366fc8c97d6f36fbdecfc1f5518/matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38", size = 8188292, upload-time = "2026-04-24T00:13:15.546Z" }, ] [[package]] @@ -3255,16 +2940,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314, upload-time = "2025-11-17T22:32:31.031Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/a1/4008f14bbc616cfb1ac5b39ea485f9c63031c4634ab3f4cf72e7541f816a/ml_dtypes-0.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c760d85a2f82e2bed75867079188c9d18dae2ee77c25a54d60e9cc79be1bc48", size = 676888, upload-time = "2025-11-17T22:31:56.907Z" }, { url = "https://files.pythonhosted.org/packages/d3/b7/dff378afc2b0d5a7d6cd9d3209b60474d9819d1189d347521e1688a60a53/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce756d3a10d0c4067172804c9cc276ba9cc0ff47af9078ad439b075d1abdc29b", size = 5036993, upload-time = "2025-11-17T22:31:58.497Z" }, { url = "https://files.pythonhosted.org/packages/eb/33/40cd74219417e78b97c47802037cf2d87b91973e18bb968a7da48a96ea44/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:533ce891ba774eabf607172254f2e7260ba5f57bdd64030c9a4fcfbd99815d0d", size = 5010956, upload-time = "2025-11-17T22:31:59.931Z" }, - { url = "https://files.pythonhosted.org/packages/e1/8b/200088c6859d8221454825959df35b5244fa9bdf263fd0249ac5fb75e281/ml_dtypes-0.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:f21c9219ef48ca5ee78402d5cc831bd58ea27ce89beda894428bc67a52da5328", size = 212224, upload-time = "2025-11-17T22:32:01.349Z" }, - { url = "https://files.pythonhosted.org/packages/8f/75/dfc3775cb36367816e678f69a7843f6f03bd4e2bcd79941e01ea960a068e/ml_dtypes-0.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:35f29491a3e478407f7047b8a4834e4640a77d2737e0b294d049746507af5175", size = 160798, upload-time = "2025-11-17T22:32:02.864Z" }, - { url = "https://files.pythonhosted.org/packages/4f/74/e9ddb35fd1dd43b1106c20ced3f53c2e8e7fc7598c15638e9f80677f81d4/ml_dtypes-0.5.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:304ad47faa395415b9ccbcc06a0350800bc50eda70f0e45326796e27c62f18b6", size = 702083, upload-time = "2025-11-17T22:32:04.08Z" }, { url = "https://files.pythonhosted.org/packages/74/f5/667060b0aed1aa63166b22897fdf16dca9eb704e6b4bbf86848d5a181aa7/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a0df4223b514d799b8a1629c65ddc351b3efa833ccf7f8ea0cf654a61d1e35d", size = 5354111, upload-time = "2025-11-17T22:32:05.546Z" }, { url = "https://files.pythonhosted.org/packages/40/49/0f8c498a28c0efa5f5c95a9e374c83ec1385ca41d0e85e7cf40e5d519a21/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531eff30e4d368cb6255bc2328d070e35836aa4f282a0fb5f3a0cd7260257298", size = 5366453, upload-time = "2025-11-17T22:32:07.115Z" }, - { url = "https://files.pythonhosted.org/packages/8c/27/12607423d0a9c6bbbcc780ad19f1f6baa2b68b18ce4bddcdc122c4c68dc9/ml_dtypes-0.5.4-cp313-cp313t-win_amd64.whl", hash = "sha256:cb73dccfc991691c444acc8c0012bee8f2470da826a92e3a20bb333b1a7894e6", size = 225612, upload-time = "2025-11-17T22:32:08.615Z" }, - { url = "https://files.pythonhosted.org/packages/e5/80/5a5929e92c72936d5b19872c5fb8fc09327c1da67b3b68c6a13139e77e20/ml_dtypes-0.5.4-cp313-cp313t-win_arm64.whl", hash = "sha256:3bbbe120b915090d9dd1375e4684dd17a20a2491ef25d640a908281da85e73f1", size = 164145, upload-time = "2025-11-17T22:32:09.782Z" }, ] [[package]] @@ -3410,15 +3089,10 @@ 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/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]] @@ -3427,14 +3101,10 @@ version = "0.21.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e3/60/f79b9b013a16fa3a58350c9295ddc6789f2e335f36ea61ed10a21b215364/msgspec-0.21.1.tar.gz", hash = "sha256:2313508e394b0d208f8f56892ca9b2799e2561329de9763b19619595a6c0f72c", size = 319193, upload-time = "2026-04-12T21:44:50.394Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/74/f11ede02839b19ff459f88e3145df5d711626ca84da4e23520cebf819367/msgspec-0.21.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:764173717a01743f007e9f74520ed281f24672c604514f7d76c1c3a10e8edb66", size = 196176, upload-time = "2026-04-12T21:44:17.613Z" }, - { url = "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:344c7cd0eaed1fb81d7959f99100ef71ec9b536881a376f11b9a6c4803365697", size = 188524, upload-time = "2026-04-12T21:44:18.815Z" }, { url = "https://files.pythonhosted.org/packages/ca/d9/9e9d7d7e5061b47540d03d640fab9b3965ba7ae49c1b2154861c8f007518/msgspec-0.21.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48943e278b3854c2f89f955ddc6f9f430d3f0784b16e47d10604ee0463cd21f5", size = 218880, upload-time = "2026-04-12T21:44:20.028Z" }, { url = "https://files.pythonhosted.org/packages/74/66/2bb344f34abb4b57e60c7c9c761994e0417b9718ec1460bf00c296f2a7ea/msgspec-0.21.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9aa659ebb0101b1cbc31461212b87e341d961f0ab0772aaf068a99e001ec4aa", size = 225050, upload-time = "2026-04-12T21:44:21.577Z" }, { url = "https://files.pythonhosted.org/packages/1a/84/7c1e412f76092277bf760cef12b7979d03314d259ab5b5cafde5d0c1722d/msgspec-0.21.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7b27d1a8ead2b6f5b0c4f2d07b8be1ccfcc041c8a0e704781edebe3ae13c484", size = 222713, upload-time = "2026-04-12T21:44:22.83Z" }, { url = "https://files.pythonhosted.org/packages/4e/27/0bba04b2b4ef05f3d068429410bc71d2cea925f1596a8f41152cccd5edb8/msgspec-0.21.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38fe93e86b61328fe544cb7fd871fad5a27c8734bfda90f65e5dbe288ae50f61", size = 227259, upload-time = "2026-04-12T21:44:24.11Z" }, - { url = "https://files.pythonhosted.org/packages/b0/2d/09574b0eea02fed2c2c1383dbaae2c7f79dc16dcd6487a886000afb5d7c4/msgspec-0.21.1-cp313-cp313-win_amd64.whl", hash = "sha256:8bc666331c35fcce05a7cd2d6221adbe0f6058f8e750711413d22793c080ac6a", size = 189857, upload-time = "2026-04-12T21:44:25.359Z" }, - { url = "https://files.pythonhosted.org/packages/46/34/105b1576ad182879914f0c821f17ee1d13abb165cb060448f96fe2aff078/msgspec-0.21.1-cp313-cp313-win_arm64.whl", hash = "sha256:42bb1241e0750c1a4346f2aa84db26c5ffd99a4eb3a954927d9f149ff2f42898", size = 175403, upload-time = "2026-04-12T21:44:26.608Z" }, ] [[package]] @@ -3443,42 +3113,14 @@ 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/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" }, ] @@ -3511,13 +3153,9 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" }, - { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" }, { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" }, { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" }, { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" }, - { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" }, - { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" }, { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" }, ] @@ -3772,20 +3410,6 @@ sandbox = [ { name = "tenacity", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] -[package.dev-dependencies] -docs = [ - { name = "myst-parser", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "nvidia-sphinx-theme", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinx", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinx-autobuild", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinx-autodoc2", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinx-copybutton", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinx-design", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinx-reredirects", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "sphinxcontrib-mermaid", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, - { name = "swagger-plugin-for-sphinx", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, -] - [package.metadata] requires-dist = [ { name = "aiohttp", specifier = ">=3.14.1" }, @@ -3834,20 +3458,6 @@ requires-dist = [ ] provides-extras = ["all", "sandbox", "dev"] -[package.metadata.requires-dev] -docs = [ - { name = "myst-parser", specifier = ">=4.0.1" }, - { name = "nvidia-sphinx-theme", specifier = ">=0.0.8" }, - { name = "sphinx", specifier = ">=8.2.3" }, - { name = "sphinx-autobuild", specifier = ">=2025.8.25" }, - { name = "sphinx-autodoc2", specifier = ">=0.5.0" }, - { name = "sphinx-copybutton", specifier = ">=0.5.2" }, - { name = "sphinx-design", specifier = ">=0.6.1" }, - { name = "sphinx-reredirects", specifier = ">=0.1.6" }, - { name = "sphinxcontrib-mermaid", specifier = ">=1.0.0" }, - { name = "swagger-plugin-for-sphinx", specifier = ">=6.0.0" }, -] - [[package]] name = "nemo-rl" source = { editable = "." } @@ -4190,24 +3800,10 @@ version = "1.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/73/79a0b22fc731989c708068427579e840a6cf4e937fe7ae5c5d0b7356ac22/ninja-1.13.0.tar.gz", hash = "sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978", size = 242558, upload-time = "2025-08-11T15:10:19.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/74/d02409ed2aa865e051b7edda22ad416a39d81a84980f544f8de717cab133/ninja-1.13.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1", size = 310125, upload-time = "2025-08-11T15:09:50.971Z" }, { url = "https://files.pythonhosted.org/packages/8e/de/6e1cd6b84b412ac1ef327b76f0641aeb5dcc01e9d3f9eee0286d0c34fd93/ninja-1.13.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630", size = 177467, upload-time = "2025-08-11T15:09:52.767Z" }, - { url = "https://files.pythonhosted.org/packages/c8/83/49320fb6e58ae3c079381e333575fdbcf1cca3506ee160a2dcce775046fa/ninja-1.13.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c", size = 187834, upload-time = "2025-08-11T15:09:54.115Z" }, - { url = "https://files.pythonhosted.org/packages/56/c7/ba22748fb59f7f896b609cd3e568d28a0a367a6d953c24c461fe04fc4433/ninja-1.13.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e", size = 202736, upload-time = "2025-08-11T15:09:55.745Z" }, - { url = "https://files.pythonhosted.org/packages/79/22/d1de07632b78ac8e6b785f41fa9aad7a978ec8c0a1bf15772def36d77aac/ninja-1.13.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988", size = 179034, upload-time = "2025-08-11T15:09:57.394Z" }, { url = "https://files.pythonhosted.org/packages/ed/de/0e6edf44d6a04dabd0318a519125ed0415ce437ad5a1ec9b9be03d9048cf/ninja-1.13.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa", size = 180716, upload-time = "2025-08-11T15:09:58.696Z" }, - { url = "https://files.pythonhosted.org/packages/54/28/938b562f9057aaa4d6bfbeaa05e81899a47aebb3ba6751e36c027a7f5ff7/ninja-1.13.0-py3-none-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1", size = 146843, upload-time = "2025-08-11T15:10:00.046Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fb/d06a3838de4f8ab866e44ee52a797b5491df823901c54943b2adb0389fbb/ninja-1.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2", size = 154402, upload-time = "2025-08-11T15:10:01.657Z" }, { url = "https://files.pythonhosted.org/packages/31/bf/0d7808af695ceddc763cf251b84a9892cd7f51622dc8b4c89d5012779f06/ninja-1.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f", size = 552388, upload-time = "2025-08-11T15:10:03.349Z" }, - { url = "https://files.pythonhosted.org/packages/9d/70/c99d0c2c809f992752453cce312848abb3b1607e56d4cd1b6cded317351a/ninja-1.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714", size = 472501, upload-time = "2025-08-11T15:10:04.735Z" }, - { url = "https://files.pythonhosted.org/packages/9f/43/c217b1153f0e499652f5e0766da8523ce3480f0a951039c7af115e224d55/ninja-1.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72", size = 638280, upload-time = "2025-08-11T15:10:06.512Z" }, - { url = "https://files.pythonhosted.org/packages/8c/45/9151bba2c8d0ae2b6260f71696330590de5850e5574b7b5694dce6023e20/ninja-1.13.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db", size = 642420, upload-time = "2025-08-11T15:10:08.35Z" }, - { url = "https://files.pythonhosted.org/packages/3c/fb/95752eb635bb8ad27d101d71bef15bc63049de23f299e312878fc21cb2da/ninja-1.13.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5", size = 585106, upload-time = "2025-08-11T15:10:09.818Z" }, - { url = "https://files.pythonhosted.org/packages/c1/31/aa56a1a286703800c0cbe39fb4e82811c277772dc8cd084f442dd8e2938a/ninja-1.13.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96", size = 707138, upload-time = "2025-08-11T15:10:11.366Z" }, { url = "https://files.pythonhosted.org/packages/34/6f/5f5a54a1041af945130abdb2b8529cbef0cdcbbf9bcf3f4195378319d29a/ninja-1.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200", size = 581758, upload-time = "2025-08-11T15:10:13.295Z" }, - { url = "https://files.pythonhosted.org/packages/95/97/51359c77527d45943fe7a94d00a3843b81162e6c4244b3579fe8fc54cb9c/ninja-1.13.0-py3-none-win32.whl", hash = "sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9", size = 267201, upload-time = "2025-08-11T15:10:15.158Z" }, - { url = "https://files.pythonhosted.org/packages/29/45/c0adfbfb0b5895aa18cec400c535b4f7ff3e52536e0403602fc1a23f7de9/ninja-1.13.0-py3-none-win_amd64.whl", hash = "sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e", size = 309975, upload-time = "2025-08-11T15:10:16.697Z" }, - { url = "https://files.pythonhosted.org/packages/df/93/a7b983643d1253bb223234b5b226e69de6cda02b76cdca7770f684b795f5/ninja-1.13.0-py3-none-win_arm64.whl", hash = "sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9", size = 290806, upload-time = "2025-08-11T15:10:18.018Z" }, ] [[package]] @@ -4241,10 +3837,8 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/49/61/7299643b9c18d669e04be7c5bcb64d985070d07553274817b45b049e7bfe/numba-0.65.0.tar.gz", hash = "sha256:edad0d9f6682e93624c00125a471ae4df186175d71fd604c983c377cdc03e68b", size = 2764131, upload-time = "2026-04-01T03:52:01.946Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/f8/eee0f1ff456218db036bfc9023995ec1f85a9dc8f2422f1594f6a87829e0/numba-0.65.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:c6334094563a456a695c812e6846288376ca02327cf246cdcc83e1bb27862367", size = 2680679, upload-time = "2026-04-01T03:51:39.491Z" }, { url = "https://files.pythonhosted.org/packages/1b/8f/3d116e4b8e92f6abace431afa4b2b944f4d65bdee83af886f5c4b263df95/numba-0.65.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b8a9008411615c69d083d1dcf477f75a5aa727b30beb16e139799e2be945cdfd", size = 3809537, upload-time = "2026-04-01T03:51:41.42Z" }, { url = "https://files.pythonhosted.org/packages/b5/2c/6a3ca4128e253cb67affe06deb47688f51ce968f5111e2a06d010e6f1fa6/numba-0.65.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af96c0cba53664efcb361528b8c75e011a6556c859c7e08424c2715201c6cf7a", size = 3508615, upload-time = "2026-04-01T03:51:43.444Z" }, - { url = "https://files.pythonhosted.org/packages/96/0e/267f9a36fb282c104a971d7eecb685b411c47dce2a740fe69cf5fc2945d9/numba-0.65.0-cp313-cp313-win_amd64.whl", hash = "sha256:6254e73b9c929dc736a1fbd3d6f5680789709a5067cae1fa7198707385129c04", size = 2749938, upload-time = "2026-04-01T03:51:45.218Z" }, ] [[package]] @@ -4253,27 +3847,14 @@ version = "2.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1d/d0a583ce4fefcc3308806a749a536c201ed6b5ad6e1322e227ee4848979d/numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50", size = 16684933, upload-time = "2026-03-29T13:19:22.47Z" }, - { url = "https://files.pythonhosted.org/packages/c1/62/2b7a48fbb745d344742c0277f01286dead15f3f68e4f359fbfcf7b48f70f/numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115", size = 14694532, upload-time = "2026-03-29T13:19:25.581Z" }, - { url = "https://files.pythonhosted.org/packages/e5/87/499737bfba066b4a3bebff24a8f1c5b2dee410b209bc6668c9be692580f0/numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af", size = 5199661, upload-time = "2026-03-29T13:19:28.31Z" }, - { url = "https://files.pythonhosted.org/packages/cd/da/464d551604320d1491bc345efed99b4b7034143a85787aab78d5691d5a0e/numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c", size = 6547539, upload-time = "2026-03-29T13:19:30.97Z" }, { url = "https://files.pythonhosted.org/packages/7d/90/8d23e3b0dafd024bf31bdec225b3bb5c2dbfa6912f8a53b8659f21216cbf/numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103", size = 15668806, upload-time = "2026-03-29T13:19:33.887Z" }, { url = "https://files.pythonhosted.org/packages/d1/73/a9d864e42a01896bb5974475438f16086be9ba1f0d19d0bb7a07427c4a8b/numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83", size = 16632682, upload-time = "2026-03-29T13:19:37.336Z" }, { url = "https://files.pythonhosted.org/packages/34/fb/14570d65c3bde4e202a031210475ae9cde9b7686a2e7dc97ee67d2833b35/numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed", size = 17019810, upload-time = "2026-03-29T13:19:40.963Z" }, { url = "https://files.pythonhosted.org/packages/8a/77/2ba9d87081fd41f6d640c83f26fb7351e536b7ce6dd9061b6af5904e8e46/numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959", size = 18357394, upload-time = "2026-03-29T13:19:44.859Z" }, - { url = "https://files.pythonhosted.org/packages/a2/23/52666c9a41708b0853fa3b1a12c90da38c507a3074883823126d4e9d5b30/numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed", size = 5959556, upload-time = "2026-03-29T13:19:47.661Z" }, - { url = "https://files.pythonhosted.org/packages/57/fb/48649b4971cde70d817cf97a2a2fdc0b4d8308569f1dd2f2611959d2e0cf/numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf", size = 12317311, upload-time = "2026-03-29T13:19:50.67Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d8/11490cddd564eb4de97b4579ef6bfe6a736cc07e94c1598590ae25415e01/numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d", size = 10222060, upload-time = "2026-03-29T13:19:54.229Z" }, - { url = "https://files.pythonhosted.org/packages/99/5d/dab4339177a905aad3e2221c915b35202f1ec30d750dd2e5e9d9a72b804b/numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5", size = 14822302, upload-time = "2026-03-29T13:19:57.585Z" }, - { url = "https://files.pythonhosted.org/packages/eb/e4/0564a65e7d3d97562ed6f9b0fd0fb0a6f559ee444092f105938b50043876/numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7", size = 5327407, upload-time = "2026-03-29T13:20:00.601Z" }, - { url = "https://files.pythonhosted.org/packages/29/8d/35a3a6ce5ad371afa58b4700f1c820f8f279948cca32524e0a695b0ded83/numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93", size = 6647631, upload-time = "2026-03-29T13:20:02.855Z" }, { url = "https://files.pythonhosted.org/packages/f4/da/477731acbd5a58a946c736edfdabb2ac5b34c3d08d1ba1a7b437fa0884df/numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e", size = 15727691, upload-time = "2026-03-29T13:20:06.004Z" }, { url = "https://files.pythonhosted.org/packages/e6/db/338535d9b152beabeb511579598418ba0212ce77cf9718edd70262cc4370/numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40", size = 16681241, upload-time = "2026-03-29T13:20:09.417Z" }, { url = "https://files.pythonhosted.org/packages/e2/a9/ad248e8f58beb7a0219b413c9c7d8151c5d285f7f946c3e26695bdbbe2df/numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e", size = 17085767, upload-time = "2026-03-29T13:20:13.126Z" }, { url = "https://files.pythonhosted.org/packages/b5/1a/3b88ccd3694681356f70da841630e4725a7264d6a885c8d442a697e1146b/numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392", size = 18403169, upload-time = "2026-03-29T13:20:17.096Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" }, - { url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" }, ] [[package]] @@ -4297,7 +3878,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/9c/da/45f78bb61f93a467ccaccf2eafbf23483bdcb29d3c5d16f8cb918be1aea0/nvidia_cublas-13.5.1.27-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bc355b10e35b01cf88e8dcc0fbe0fd1ef86a05fddae78a44dc133d7e63eaf973", size = 515580892, upload-time = "2026-05-26T16:43:17.967Z" }, { url = "https://files.pythonhosted.org/packages/ce/0d/cc77458e8fb0634597e3994650c2853ee785f2fc61bf370bbb304021cca1/nvidia_cublas-13.5.1.27-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:db3a1f0c8bc24945a4d195ba199d83f27e650ffdfc0c32e6b8362c314f14d553", size = 407748877, upload-time = "2026-05-26T16:44:19.938Z" }, - { url = "https://files.pythonhosted.org/packages/99/73/2c08fc3802d72931af348e8f1cf3a0b013e5dd91a6dcc235af8f52cfcb87/nvidia_cublas-13.5.1.27-py3-none-win_amd64.whl", hash = "sha256:234a2e89682080421431d2f2ea422fc2ad7d0b462336ccdfde76c559c906c670", size = 391875500, upload-time = "2026-05-26T17:06:29.178Z" }, ] [[package]] @@ -4307,7 +3887,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/7a/9cb8a7fb87a85b11e8753548ae1422be847c5dddf3ca9ff5b080b309e271/nvidia_cuda_cccl-13.3.3.3.1-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4dbc9dd84fbaeae267cbd80a9ed76d35171dba78639695dbdff0bae50e4503fa", size = 3453010, upload-time = "2026-05-26T16:27:45.179Z" }, { url = "https://files.pythonhosted.org/packages/fe/fb/195d50d25ab68a76b817ffc68c45b1fb828598ce35a8e5c1736060628dab/nvidia_cuda_cccl-13.3.3.3.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40ba1fa0b2c694ddc06cc791ed5c8bdad4638e2735b784960d68ac3086399c97", size = 3453013, upload-time = "2026-05-26T16:28:08.209Z" }, - { url = "https://files.pythonhosted.org/packages/57/44/37cf1596880e7712f357b3f4991cd34d0f322c26e2bc814d1bdeffb2f420/nvidia_cuda_cccl-13.3.3.3.1-py3-none-win_amd64.whl", hash = "sha256:d1ac746f57ab83403f01e64e2b292101caf5b3445babca9f1c1c34f344766adf", size = 3452993, upload-time = "2026-05-26T16:58:59.166Z" }, ] [[package]] @@ -4317,7 +3896,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151", size = 10310827, upload-time = "2025-09-04T08:26:42.012Z" }, { url = "https://files.pythonhosted.org/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8", size = 10715597, upload-time = "2025-09-04T08:26:51.312Z" }, - { url = "https://files.pythonhosted.org/packages/ad/df/b74b10025c1205695c5676373f2edd3e87a7202cc62ead0dfbc373b0f6ea/nvidia_cuda_cupti-13.0.85-py3-none-win_amd64.whl", hash = "sha256:683f58d301548deeefcb8f6fac1b8d907691b9d8b18eccab417f51e362102f00", size = 7736776, upload-time = "2025-09-04T08:38:08.38Z" }, ] [[package]] @@ -4327,7 +3905,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575", size = 90215200, upload-time = "2025-09-04T08:28:44.204Z" }, { url = "https://files.pythonhosted.org/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b", size = 43015449, upload-time = "2025-09-04T08:28:20.239Z" }, - { url = "https://files.pythonhosted.org/packages/4a/af/345fedb9f4c76c84ab4fa445b36bd4048a4d9db60e6bc76b4f913ff4b852/nvidia_cuda_nvrtc-13.0.88-py3-none-win_amd64.whl", hash = "sha256:6bcd4e7f8e205cbe644f5a98f2f799bef9556fefc89dd786e79a16312ce49872", size = 76807835, upload-time = "2025-09-04T08:39:15.274Z" }, ] [[package]] @@ -4337,7 +3914,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55", size = 2261060, upload-time = "2025-10-09T08:55:15.78Z" }, { url = "https://files.pythonhosted.org/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548", size = 2243632, upload-time = "2025-10-09T08:55:36.117Z" }, - { url = "https://files.pythonhosted.org/packages/b7/94/6b867483bec07da24ffa32736c79fabb94ef3a7af4d787a9d4a974868576/nvidia_cuda_runtime-13.0.96-py3-none-win_amd64.whl", hash = "sha256:f79298c8a098cec150a597c8eba58ecdab96e3bdc4b9bc4f9983635031740492", size = 2927037, upload-time = "2025-10-09T09:04:23.782Z" }, ] [[package]] @@ -4350,7 +3926,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/56/c5/83384d846b2fd17c44bd499b36c75a45ed4f095fbbb2252294e89cea5c5c/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e31454ae00094b0c55319d9d15b6fa2fc50a9e1c0f5c8c80fb75258234e731e1", size = 444574296, upload-time = "2026-03-09T19:28:27.751Z" }, { url = "https://files.pythonhosted.org/packages/6e/5e/edb9c0ae051602c3ccaffe424256463636d639e27d7f302dde9975ef9e7a/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0c45dd8eeb50b603f07995b1b300c62ffe6a1980482b82b3bcf94a4ca9d49304", size = 366173588, upload-time = "2026-03-09T19:29:34.474Z" }, - { url = "https://files.pythonhosted.org/packages/78/39/21507455b1bca8b5702a9e9fc6ce73735f216f558dac2c9ede58e4d456b8/nvidia_cudnn_cu13-9.20.0.48-py3-none-win_amd64.whl", hash = "sha256:af8139732b99c0118be65ea5aac97f0d46018f8c552889e49d2fb0c6261a4a24", size = 350712614, upload-time = "2026-03-09T19:31:11.398Z" }, ] [[package]] @@ -4360,7 +3935,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/55/bc/eed9ae32a00a7c501f6ca3b93782fe50b3c9fd9168d500586b761f42f2bd/nvidia_cudnn_frontend-1.23.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa35283da087d65cdc1ea12a7872f90ed5a725e8ed0d8009b82d801bf92ad0ae", size = 2935910, upload-time = "2026-04-29T19:15:20.96Z" }, { url = "https://files.pythonhosted.org/packages/ad/14/4e0b66650d68f32d4c7b46e8b33cb98e69497f3fc1a9f63a02328a45d694/nvidia_cudnn_frontend-1.23.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8b817a0deb94f394b082f1ca389829ec0c9c85411a1092f08719c66bbaa1e39", size = 3082233, upload-time = "2026-04-29T19:15:48.864Z" }, - { url = "https://files.pythonhosted.org/packages/e3/c8/f5fad0e91e43df3a85e7c29b15bd11b587f27a096b7096abd3b3fbc8f761/nvidia_cudnn_frontend-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:b78c70b40c389f9e844eae73f5686bb72b15763399aede5c3995d81e78c5547c", size = 2494849, upload-time = "2026-04-29T19:16:11.571Z" }, ] [[package]] @@ -4373,7 +3947,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, { url = "https://files.pythonhosted.org/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3", size = 214085489, upload-time = "2025-09-04T08:31:56.044Z" }, - { url = "https://files.pythonhosted.org/packages/85/b2/f8af21a2ed1beed337a6a02c5a28aeb85441f4d578ec3d529543c775ea4b/nvidia_cufft-12.0.0.61-py3-none-win_amd64.whl", hash = "sha256:2abce5b39d2f5ae12730fb7e5db6696533e36c26e2d3e8fd1750bdd2853364eb", size = 213342123, upload-time = "2025-09-04T08:40:51.145Z" }, ] [[package]] @@ -4392,7 +3965,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a", size = 61962106, upload-time = "2025-08-04T10:21:41.128Z" }, { url = "https://files.pythonhosted.org/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc", size = 59544258, upload-time = "2025-08-04T10:22:03.992Z" }, - { url = "https://files.pythonhosted.org/packages/99/27/72103153b1ffc00e09fdc40ac970235343dcd1ea8bd762e84d2d73219ffa/nvidia_curand-10.4.0.35-py3-none-win_amd64.whl", hash = "sha256:65b1710aa6961d326b411e314b374290904c5ddf41dc3f766ebc3f1d7d4ca69f", size = 55242481, upload-time = "2025-08-04T10:30:41.831Z" }, ] [[package]] @@ -4407,7 +3979,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, { url = "https://files.pythonhosted.org/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112", size = 200941980, upload-time = "2025-09-04T08:33:22.767Z" }, - { url = "https://files.pythonhosted.org/packages/99/ef/332a0101260ca78a1daef046bf0b06199e8ed4dac1d2aa698289c358169c/nvidia_cusolver-12.0.4.66-py3-none-win_amd64.whl", hash = "sha256:16515bd33a8e76bb54d024cfa068fa68d30e80fc34b9e1090813ea9362e0cb65", size = 193551444, upload-time = "2025-09-04T08:41:46.813Z" }, ] [[package]] @@ -4420,7 +3991,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, { url = "https://files.pythonhosted.org/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b", size = 145942937, upload-time = "2025-09-04T08:33:58.029Z" }, - { url = "https://files.pythonhosted.org/packages/02/b0/b043d6f3480f102f885cf87fc3ffd3edcb5e23b855025a50e2ef4d059185/nvidia_cusparse-12.6.3.3-py3-none-win_amd64.whl", hash = "sha256:cbcf42feb737bd7ec15b4c0a63e62351886bd3f975027b8815d7f720a2b5ea79", size = 143783033, upload-time = "2025-09-04T08:42:12.391Z" }, ] [[package]] @@ -4430,7 +4000,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/46/10/8dcd1175260706a2fc92a16a52e306b71d4c1ea0b0cc4a9484183399818a/nvidia_cusparselt_cu13-0.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:400c6ed1cf6780fc6efedd64ec9f1345871767e6a1a0a552a1ea0578117ea77c", size = 220791277, upload-time = "2025-08-13T19:22:40.982Z" }, { url = "https://files.pythonhosted.org/packages/fd/53/43b0d71f4e702fa9733f8b4571fdca50a8813f1e450b656c239beff12315/nvidia_cusparselt_cu13-0.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:25e30a8a7323935d4ad0340b95a0b69926eee755767e8e0b1cf8dd85b197d3fd", size = 169884119, upload-time = "2025-08-13T19:23:41.967Z" }, - { url = "https://files.pythonhosted.org/packages/57/de/8f0578928b9b1246d7b1324db0528e6b9f9fb54496a49f40bf71f09f1a27/nvidia_cusparselt_cu13-0.8.0-py3-none-win_amd64.whl", hash = "sha256:e80212ed7b1afc97102fbb2b5c82487aa73f6a0edfa6d26c5a152593e520bb8f", size = 156459710, upload-time = "2025-08-13T19:24:18.043Z" }, ] [[package]] @@ -4525,7 +4094,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/56/7a/123e033aaff487c77107195fa5a2b8686795ca537935a24efae476c41f05/nvidia_nvjitlink-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:13a74f429e23b921c1109976abefacc69835f2f433ebd323d3946e11d804e47b", size = 40713933, upload-time = "2025-09-04T08:35:43.553Z" }, { url = "https://files.pythonhosted.org/packages/ab/2c/93c5250e64df4f894f1cbb397c6fd71f79813f9fd79d7cd61de3f97b3c2d/nvidia_nvjitlink-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e931536ccc7d467a98ba1d8b89ff7fa7f1fa3b13f2b0069118cd7f47bff07d0c", size = 38768748, upload-time = "2025-09-04T08:35:20.008Z" }, - { url = "https://files.pythonhosted.org/packages/e4/01/07530b0e37546231052e30234540289c42eaffa486f1a34a87fed340157b/nvidia_nvjitlink-13.0.88-py3-none-win_amd64.whl", hash = "sha256:634e96e3da9ef845ae744097a1f289238ecf946ce0b82e93cdce14b9782e682f", size = 36035115, upload-time = "2025-09-04T08:43:03.001Z" }, ] [[package]] @@ -4547,7 +4115,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4", size = 148047, upload-time = "2025-09-04T08:29:01.761Z" }, { url = "https://files.pythonhosted.org/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6", size = 148878, upload-time = "2025-09-04T08:28:53.627Z" }, - { url = "https://files.pythonhosted.org/packages/d2/50/0e2220f8620a177de994211186ffc5bfa9f2ce1e1282797f8f90096f9f88/nvidia_nvtx-13.0.85-py3-none-win_amd64.whl", hash = "sha256:d66ea44254dd3c6eacc300047af6e1288d2269dd072b417e0adffbf479e18519", size = 137066, upload-time = "2025-09-04T08:39:25.649Z" }, ] [[package]] @@ -4605,10 +4172,8 @@ sdist = { url = "https://files.pythonhosted.org/packages/92/dd/692765e87de30bae1 wheels = [ { url = "https://files.pythonhosted.org/packages/05/c9/8341224b8284f7deb6a634119939de5885adc421e64b6743693b30da2186/nvtx-0.2.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d28660d9c46f8ba750d781572b6aa5a1e6221abba224ab32d7fb32c2d0fd67df", size = 780787, upload-time = "2026-03-18T10:10:40.634Z" }, { url = "https://files.pythonhosted.org/packages/b1/c0/4a5bb7897918de7c7e0191d9342df8ae4cb797ff07276e0f20d13e497ce7/nvtx-0.2.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10749686633f880ad53dcdbb2179fad41b45dcf5b7631d4a1070a577577bd386", size = 782575, upload-time = "2026-03-18T10:13:57.3Z" }, - { url = "https://files.pythonhosted.org/packages/38/b9/6b381ac7c5a3ded331aebbf25f8959d19b51d320fb2514c76c6b6edddaaa/nvtx-0.2.15-cp313-cp313-win_amd64.whl", hash = "sha256:a6650b029263d12f8427a4dee8bd59cb9c91bccb60543bfcb20bc2b00fdcd672", size = 128764, upload-time = "2026-03-18T10:02:33.343Z" }, { url = "https://files.pythonhosted.org/packages/75/69/a9acb6d95d2e0e381b2956544768528dd8d7a9e827af8c2014169d838284/nvtx-0.2.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25813ead4fff4d3a6e04f69a72507b096a6bdbecefa369f1100b0e584767bca8", size = 833375, upload-time = "2026-03-18T10:06:31.955Z" }, { url = "https://files.pythonhosted.org/packages/38/56/c7e8645061cc2fc23f3a54f33e1e340df59216f07dcfb97d46b8ae7dd26c/nvtx-0.2.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3741edac4678b92f03d22a3f0a2dfd469f422f85e63db71b038e02525b2404ad", size = 788639, upload-time = "2026-03-18T10:12:01.69Z" }, - { url = "https://files.pythonhosted.org/packages/96/03/fadd82acdbca6d1c49ac517081a0c3714346f52f4c7e1d4449d77605b4aa/nvtx-0.2.15-cp313-cp313t-win_amd64.whl", hash = "sha256:8be06c3c8c267eba56a0396366b9593092e0b75ea8d3702b303d48c0a1662f0e", size = 142609, upload-time = "2026-03-18T10:01:48.832Z" }, ] [[package]] @@ -4617,19 +4182,10 @@ version = "0.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2e/2f/f83afaab7945509d72245b2b00af0b4834ce78fdd2d9ae9f0ad1a3036a91/obstore-0.11.0.tar.gz", hash = "sha256:a2f55163bcd348b4a60d12e6893eac50eddc742bad8032a1705d49140b992204", size = 130565, upload-time = "2026-06-25T18:29:49.405Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/b2/00c213e7e5ca8065f97e37e55294adab836e3f6a88b23e4029069aaecf95/obstore-0.11.0-cp311-abi3-macosx_10_12_x86_64.whl", hash = "sha256:42f36546c7ac44dbab1173d2330a8a1b1a3f0e37950e553b8c904e3dd0744b25", size = 5491935, upload-time = "2026-06-25T18:28:32.029Z" }, - { url = "https://files.pythonhosted.org/packages/ac/37/6a6b9a5e15a8a37c24d14317a87648097c4888593b588510c03c030d2e90/obstore-0.11.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:687bb9d3962d568b7c439c5d0c6fea19b2749862a8e5c8eebd0c058c4eccde9e", size = 4672619, upload-time = "2026-06-25T18:28:33.852Z" }, - { url = "https://files.pythonhosted.org/packages/28/f9/6745ce8c4f7bfac19dc14a4438b48a2e93a689b92b0cecfc695e41a4e8b1/obstore-0.11.0-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:010b51578c7514a41719d795cdb7a1e6529be509dac3772e477187a59422bb97", size = 5072806, upload-time = "2026-06-25T18:28:36.127Z" }, - { url = "https://files.pythonhosted.org/packages/6c/18/991d3b3cdd851c0225e55f3dc45b47fd9e249827d188995011469f805132/obstore-0.11.0-cp311-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfaa8129a3f5d8518a3a75184d4b02348db0f6263177cd1f0951f6568243cc9e", size = 5303777, upload-time = "2026-06-25T18:28:37.89Z" }, - { url = "https://files.pythonhosted.org/packages/8d/e9/90e56015a45b5e56a84fc3188c4e5fb088b288d41992c73a629e10df6760/obstore-0.11.0-cp311-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c790a5cb9ff2970d1f464a6a708d734dce9939e9f668cb6708c5dba5d61589b2", size = 5493871, upload-time = "2026-06-25T18:28:39.981Z" }, - { url = "https://files.pythonhosted.org/packages/66/02/f1744091d59ce71c5523174eb860fbb298275c901e89b9ea6fbf3e654a33/obstore-0.11.0-cp311-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:827113e12fe8088e0281a9d57b90b2b8dbc8a6ffe3b15dadb9baa5feb3d266c1", size = 5361913, upload-time = "2026-06-25T18:28:42.089Z" }, { url = "https://files.pythonhosted.org/packages/5d/59/3f47822683ee2b6db8685faa25829946d6343a561251ec2704548455d946/obstore-0.11.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2ff6d3ed553298828fb760b4aef6347fbcc7b5c5e3ce3f8381ce805c370021a", size = 5638724, upload-time = "2026-06-25T18:28:43.897Z" }, { url = "https://files.pythonhosted.org/packages/23/50/1df335fdf9b527b3933f1e94ab6fc720ad314260fab8591cb0b6668ff192/obstore-0.11.0-cp311-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:39d04b324fcf984e7050734ebda77b81764025b0c011750201a0d8954087f7aa", size = 5413508, upload-time = "2026-06-25T18:28:45.624Z" }, { url = "https://files.pythonhosted.org/packages/de/dc/a259aba149b841ca7c91fea177df9972a60a636b54077beed1a35b254994/obstore-0.11.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:37c0d15d775b1370ef5204ee3919a5ddf7e2592d11815213105f8db031f2ab8d", size = 5619995, upload-time = "2026-06-25T18:28:47.599Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b4/ec25fdb4d6b060bc6eea647fc0e88f75fcc20fe8d16d67fb0dbe999d323b/obstore-0.11.0-cp311-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:7f468caf9b6e0f12ff151e5fe618de5fc9192befa9bd02734b06de4efd2e49f6", size = 5299512, upload-time = "2026-06-25T18:28:49.629Z" }, - { url = "https://files.pythonhosted.org/packages/a8/e5/29be060d06ec13e2af3d1b6cfb77b7c37f8be6c56b77295c945fefad73e4/obstore-0.11.0-cp311-abi3-musllinux_1_2_i686.whl", hash = "sha256:42d8e8fad85be8ee488c1a9a9b7c6a42128abb84e67175da40d3d1165c1846df", size = 5427026, upload-time = "2026-06-25T18:28:51.317Z" }, { url = "https://files.pythonhosted.org/packages/57/b7/577a965f440e9ea64243518663f9d16be7df8eafc7123818e8e841fa21ce/obstore-0.11.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9c8fd2a544e2e0b926669c47fcfb8d2314e234abc240ea165dae04ee42e1d7ac", size = 5869187, upload-time = "2026-06-25T18:28:53.166Z" }, - { url = "https://files.pythonhosted.org/packages/e2/18/8fdbaee22bfd5b9c44e1fdff8ca0508e2fe60c42bf9fc85f0c9c27b4ecf2/obstore-0.11.0-cp311-abi3-win_amd64.whl", hash = "sha256:6fb3d4678c0f4242d3109362e9b1df5d7b27765f43d5aacb2e81af53a75cb9ef", size = 5329384, upload-time = "2026-06-25T18:28:55.305Z" }, ] [[package]] @@ -4657,17 +4213,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/c5/93/942d2a0f6a70538eea042ce0445c8aefd46559ad153469986f29a743c01c/onnx-1.21.0.tar.gz", hash = "sha256:4d8b67d0aaec5864c87633188b91cc520877477ec0254eda122bef8be43cd764", size = 12074608, upload-time = "2026-03-27T21:33:36.118Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ae/cb644ec84c25e63575d9d8790fdcc5d1a11d67d3f62f872edb35fa38d158/onnx-1.21.0-cp312-abi3-macosx_12_0_universal2.whl", hash = "sha256:fc2635400fe39ff37ebc4e75342cc54450eadadf39c540ff132c319bf4960095", size = 17965930, upload-time = "2026-03-27T21:32:48.089Z" }, { url = "https://files.pythonhosted.org/packages/6f/b6/eeb5903586645ef8a49b4b7892580438741acc3df91d7a5bd0f3a59ea9cb/onnx-1.21.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9003d5206c01fa2ff4b46311566865d8e493e1a6998d4009ec6de39843f1b59b", size = 17531344, upload-time = "2026-03-27T21:32:50.837Z" }, { url = "https://files.pythonhosted.org/packages/a7/00/4823f06357892d1e60d6f34e7299d2ba4ed2108c487cc394f7ce85a3ff14/onnx-1.21.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9261bd580fb8548c9c37b3c6750387eb8f21ea43c63880d37b2c622e1684285", size = 17613697, upload-time = "2026-03-27T21:32:54.222Z" }, - { url = "https://files.pythonhosted.org/packages/23/1d/391f3c567ae068c8ac4f1d1316bae97c9eb45e702f05975fe0e17ad441f0/onnx-1.21.0-cp312-abi3-win32.whl", hash = "sha256:9ea4e824964082811938a9250451d89c4ec474fe42dd36c038bfa5df31993d1e", size = 16287200, upload-time = "2026-03-27T21:32:57.277Z" }, - { url = "https://files.pythonhosted.org/packages/9c/a6/5eefbe5b40ea96de95a766bd2e0e751f35bdea2d4b951991ec9afaa69531/onnx-1.21.0-cp312-abi3-win_amd64.whl", hash = "sha256:458d91948ad9a7729a347550553b49ab6939f9af2cddf334e2116e45467dc61f", size = 16441045, upload-time = "2026-03-27T21:33:00.081Z" }, - { url = "https://files.pythonhosted.org/packages/63/c4/0ed8dc037a39113d2a4d66e0005e07751c299c46b993f1ad5c2c35664c20/onnx-1.21.0-cp312-abi3-win_arm64.whl", hash = "sha256:ca14bc4842fccc3187eb538f07eabeb25a779b39388b006db4356c07403a7bbb", size = 16403134, upload-time = "2026-03-27T21:33:03.987Z" }, - { url = "https://files.pythonhosted.org/packages/f8/89/0e1a9beb536401e2f45ac88735e123f2735e12fc7b56ff6c11727e097526/onnx-1.21.0-cp313-cp313t-macosx_12_0_universal2.whl", hash = "sha256:257d1d1deb6a652913698f1e3f33ef1ca0aa69174892fe38946d4572d89dd94f", size = 17975430, upload-time = "2026-03-27T21:33:07.005Z" }, { url = "https://files.pythonhosted.org/packages/ec/46/e6dc71a7b3b317265591b20a5f71d0ff5c0d26c24e52283139dc90c66038/onnx-1.21.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7cd7cb8f6459311bdb557cbf6c0ccc6d8ace11c304d1bba0a30b4a4688e245f8", size = 17537435, upload-time = "2026-03-27T21:33:09.765Z" }, { url = "https://files.pythonhosted.org/packages/49/2e/27affcac63eaf2ef183a44fd1a1354b11da64a6c72fe6f3fdcf5571bcee5/onnx-1.21.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b58a4cfec8d9311b73dc083e4c1fa362069267881144c05139b3eba5dc3a840", size = 17617687, upload-time = "2026-03-27T21:33:12.619Z" }, - { url = "https://files.pythonhosted.org/packages/1c/5c/ac8ed15e941593a3672ce424280b764979026317811f2e8508432bfc3429/onnx-1.21.0-cp313-cp313t-win_amd64.whl", hash = "sha256:1a9baf882562c4cebf79589bebb7cd71a20e30b51158cac3e3bbaf27da6163bd", size = 16449402, upload-time = "2026-03-27T21:33:15.555Z" }, - { url = "https://files.pythonhosted.org/packages/0e/aa/d2231e0dcaad838217afc64c306c8152a080134d2034e247cc973d577674/onnx-1.21.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bba12181566acf49b35875838eba49536a327b2944664b17125577d230c637ad", size = 16408273, upload-time = "2026-03-27T21:33:18.599Z" }, ] [[package]] @@ -4750,19 +4299,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/92/94/01509d510bebf6606614e51113e5a415ced15b8f34aa98a8bf2539314650/openai_harmony-0.0.4.tar.gz", hash = "sha256:5c67ac6df349236fb7b64f57c3dbb0273efcdca24314daa108f2a482c427106c", size = 279848, upload-time = "2025-08-09T01:43:24.974Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/3e/6bb75a4d15a6aad0ba1b23193ca0d2c202cc1f3364ba840833374b7c9c1a/openai_harmony-0.0.4-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3586d90c899cd41f8624e7b82a48c289f6e4be56c66304ecaf3a0ba88963a73f", size = 2772770, upload-time = "2025-08-09T01:43:14.839Z" }, - { url = "https://files.pythonhosted.org/packages/34/41/2f256fba6762d028ed6f935f0015f71d81927a52b9a1c873679a409b72bf/openai_harmony-0.0.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef21a1e2384a65c62d5ec5e1cded9fe026f1d032d5c5d725110d1a8d330d8f54", size = 2633682, upload-time = "2025-08-09T01:43:12.681Z" }, { url = "https://files.pythonhosted.org/packages/05/88/ade63bd8f36603610040e7cc086bc134d57a99a742e05f7fcddfdf822ee1/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf2344366f10981bbc0f6d9949a0b2bb87151d209ed295943ed6ad8eda37932", size = 2963206, upload-time = "2025-08-09T01:43:02.433Z" }, - { url = "https://files.pythonhosted.org/packages/8e/ef/a65a0ff177fdf67bc0afd18bb9e7ad690d1b553a8eb5ebf27f601b22dbd0/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d8d16d84702059833fb03b841b28c25600c54e83cadccef79af44e1c81166b1", size = 2724854, upload-time = "2025-08-09T01:43:04.606Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a1/ebaf0f55601a98609641283884d52dbfe9a1cf34b04f1cf80acb1560ab74/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97f1fe3909733212cc6b36f0f199b1421a9c57b79ec665f0322bd604cec47340", size = 2984312, upload-time = "2025-08-09T01:43:08.908Z" }, - { url = "https://files.pythonhosted.org/packages/45/24/246f6f470bfbc89a117714b68f27cdaee12b31166237a227cc657780cc1d/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:567cc568b6bf7b4d041b0c9aa7d6b2c9394f8af6065bc87fa6d23f207b5af9a7", size = 3447870, upload-time = "2025-08-09T01:43:06.734Z" }, { url = "https://files.pythonhosted.org/packages/1f/ec/dcdcace0ffcf3a532cca910e0c351b62d3a7decf0b091ea8cf856d2a67a6/openai_harmony-0.0.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31e9bcac0902a309e2fc688e52f247eec7fffcd00d17e958b9a83a8fea6519c2", size = 3049306, upload-time = "2025-08-09T01:43:11.019Z" }, { url = "https://files.pythonhosted.org/packages/ad/39/172f1048d935db1523a82b45fee5231ad6c622645e566706e6bcf3731da8/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:96a63199c0d81095b5d5d1ae8ca82b64c1c13d18d4e30323ae9e8ab31bc80a3d", size = 3121347, upload-time = "2025-08-09T01:43:16.705Z" }, - { url = "https://files.pythonhosted.org/packages/6b/36/8ee4ca5d0b25587121fd3621e6a6106fba80218cb6d159e1670aeb2b22ef/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:d38f2639f6bf7c3c34a5dfd79e29075811ae2fa9b895a63e76767f74a47a971e", size = 2952326, upload-time = "2025-08-09T01:43:18.841Z" }, - { url = "https://files.pythonhosted.org/packages/ae/a0/ec8906393968679e269e23e957e11ff419978d1d077fb9af9561b161c988/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:038f1d6772d1be5213b36ae76e5d042022395ec35c428a73ccb8b839b2cecf6a", size = 3015832, upload-time = "2025-08-09T01:43:21.076Z" }, { url = "https://files.pythonhosted.org/packages/a8/bd/aa9e6e5cf140716dbcae17402fac2a81a9ebb3f934059ac0eec61cb447fc/openai_harmony-0.0.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:15e6d53a66502491a3675a536df30e271f976e6c5efe68250a65191efcb85c4f", size = 3221129, upload-time = "2025-08-09T01:43:23.146Z" }, - { url = "https://files.pythonhosted.org/packages/5a/22/2c7e1728689c7fa98a259ca2d14e718ea7af964516a617a9784f0d35d88a/openai_harmony-0.0.4-cp38-abi3-win32.whl", hash = "sha256:b9ee9e9ab6a237cebbe16563c787a6e83f3fcc034075c3d321dab94448426282", size = 2077125, upload-time = "2025-08-09T01:43:28.91Z" }, - { url = "https://files.pythonhosted.org/packages/e7/93/3a08a06ff3bde7f4c264f86d437e6a5c49792a6e362383b3a669f39c9690/openai_harmony-0.0.4-cp38-abi3-win_amd64.whl", hash = "sha256:746f751de5033b3dbcfcd4a726a4c56ce452c593ad3d54472d8597ce8d8b6d44", size = 2444821, upload-time = "2025-08-09T01:43:26.846Z" }, ] [[package]] @@ -4796,14 +4336,10 @@ dependencies = [ { name = "numpy", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/79/42/2310883be3b8826ac58c3f2787b9358a2d46923d61f88fedf930bc59c60c/opencv_python_headless-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:1a7d040ac656c11b8c38677cc8cccdc149f98535089dbe5b081e80a4e5903209", size = 46247192, upload-time = "2026-02-05T07:01:35.187Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1e/6f9e38005a6f7f22af785df42a43139d0e20f169eb5787ce8be37ee7fcc9/opencv_python_headless-4.13.0.92-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:3e0a6f0a37994ec6ce5f59e936be21d5d6384a4556f2d2da9c2f9c5dc948394c", size = 32568914, upload-time = "2026-02-05T07:01:51.989Z" }, { url = "https://files.pythonhosted.org/packages/21/76/9417a6aef9def70e467a5bf560579f816148a4c658b7d525581b356eda9e/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c8cfc8e87ed452b5cecb9419473ee5560a989859fe1d10d1ce11ae87b09a2cb", size = 33703709, upload-time = "2026-02-05T10:24:46.469Z" }, { url = "https://files.pythonhosted.org/packages/92/ce/bd17ff5772938267fd49716e94ca24f616ff4cb1ff4c6be13085108037be/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0525a3d2c0b46c611e2130b5fdebc94cf404845d8fa64d2f3a3b679572a5bd22", size = 56016764, upload-time = "2026-02-05T10:26:48.904Z" }, { url = "https://files.pythonhosted.org/packages/8f/b4/b7bcbf7c874665825a8c8e1097e93ea25d1f1d210a3e20d4451d01da30aa/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb60e36b237b1ebd40a912da5384b348df8ed534f6f644d8e0b4f103e272ba7d", size = 35010236, upload-time = "2026-02-05T10:28:11.031Z" }, { url = "https://files.pythonhosted.org/packages/4b/33/b5db29a6c00eb8f50708110d8d453747ca125c8b805bc437b289dbdcc057/opencv_python_headless-4.13.0.92-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0bd48544f77c68b2941392fcdf9bcd2b9cdf00e98cb8c29b2455d194763cf99e", size = 60391106, upload-time = "2026-02-05T10:30:14.236Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c3/52cfea47cd33e53e8c0fbd6e7c800b457245c1fda7d61660b4ffe9596a7f/opencv_python_headless-4.13.0.92-cp37-abi3-win32.whl", hash = "sha256:a7cf08e5b191f4ebb530791acc0825a7986e0d0dee2a3c491184bd8599848a4b", size = 30812232, upload-time = "2026-02-05T07:02:29.594Z" }, - { url = "https://files.pythonhosted.org/packages/4a/90/b338326131ccb2aaa3c2c85d00f41822c0050139a4bfe723cfd95455bd2d/opencv_python_headless-4.13.0.92-cp37-abi3-win_amd64.whl", hash = "sha256:77a82fe35ddcec0f62c15f2ba8a12ecc2ed4207c17b0902c7a3151ae29f37fb6", size = 40070414, upload-time = "2026-02-05T07:02:26.448Z" }, ] [[package]] @@ -5007,21 +4543,10 @@ version = "3.11.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", size = 5599163, upload-time = "2026-05-06T15:11:08.309Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/33/93fcc25907235c344ae73122f8a4e01d2d393ef062b4af7d2e2487a32c37/orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021", size = 228458, upload-time = "2026-05-06T15:10:20.079Z" }, - { url = "https://files.pythonhosted.org/packages/8f/27/b1e6dadb3c080313c03fdd8067b85e6a0460c7d8d6a1c3984ef77b904e4d/orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c", size = 128368, upload-time = "2026-05-06T15:10:21.549Z" }, { url = "https://files.pythonhosted.org/packages/21/0f/c9ede0bf052f6b4051e64a7d4fa91b725cccf8321a6a786e86eb03519f00/orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81", size = 132070, upload-time = "2026-05-06T15:10:23.371Z" }, - { url = "https://files.pythonhosted.org/packages/fd/26/d398e28048dc18205bbe812f2c88cb9b40313db2470778e25964796458fe/orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a", size = 127892, upload-time = "2026-05-06T15:10:24.714Z" }, - { url = "https://files.pythonhosted.org/packages/66/60/52b0054c4c700d5aa7fc5b7ca96917400d8f061307778578e67a10e25852/orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10", size = 135217, upload-time = "2026-05-06T15:10:26.084Z" }, - { url = "https://files.pythonhosted.org/packages/d5/97/1e3dc2b2a28b7b2528f403d2fc1d79ec5f39af3bc143ab65d3ec26426385/orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362", size = 145980, upload-time = "2026-05-06T15:10:28.062Z" }, - { url = "https://files.pythonhosted.org/packages/fc/39/31fbfe7850f2de32dee7e7e5c09f26d403ab01e440ac96001c6b01ad3c99/orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97", size = 132738, upload-time = "2026-05-06T15:10:29.727Z" }, { url = "https://files.pythonhosted.org/packages/a1/08/dca0082dd2a194acb93e5457e73455388e2e2ca464a2672449a9ddbb679d/orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218", size = 134033, upload-time = "2026-05-06T15:10:31.152Z" }, { url = "https://files.pythonhosted.org/packages/11/d4/5bdb0626801230139987385554c5d4c42255218ac906525bf4347f22cd95/orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9", size = 141492, upload-time = "2026-05-06T15:10:32.641Z" }, - { url = "https://files.pythonhosted.org/packages/fa/88/a21fb53b3ede6703aede6dce4710ed4111e5b201cfa6bbff5e544f9d47d7/orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677", size = 415087, upload-time = "2026-05-06T15:10:34.438Z" }, - { url = "https://files.pythonhosted.org/packages/3d/57/1b30daf70f0d8180e9a73cefbfbdd99e4bf19eb020466502b01fba7e0e50/orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4", size = 148031, upload-time = "2026-05-06T15:10:36.358Z" }, { url = "https://files.pythonhosted.org/packages/04/83/45fbb6d962e260807f99441db9613cee868ceda4baceda59b3720a563f97/orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0", size = 136915, upload-time = "2026-05-06T15:10:38.013Z" }, - { url = "https://files.pythonhosted.org/packages/5f/cc/2d10025f9056d376e4127ec05a5808b218d46f035fdc08178a5411b34250/orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32", size = 131613, upload-time = "2026-05-06T15:10:39.569Z" }, - { url = "https://files.pythonhosted.org/packages/67/bd/2775ff28bfe883b9aa1ff348300542eb2ef1ee18d8ae0e3a49846817a865/orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979", size = 127086, upload-time = "2026-05-06T15:10:41.262Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/d26799e580939e32a7da9a39531bc9e58e15ca32ffaa6a8cb3e9bb0d22cd/orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254", size = 126696, upload-time = "2026-05-06T15:10:42.651Z" }, ] [[package]] @@ -5051,14 +4576,8 @@ version = "0.2.14" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6a/04/4a0812eb27c086cfd2e66e7ec9150f33e105912a9b7f8b335e3479f03a06/outlines_core-0.2.14.tar.gz", hash = "sha256:64808deed1591ca3029ff64346ceb974cd5d780c916ea82504951fe83523039e", size = 191539, upload-time = "2026-01-09T15:59:10.016Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/9d/e6c81c975c123f0639d5f6909c987e510d43e07c2e1e6495b21639c4dec6/outlines_core-0.2.14-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8b3e8d668188282a1f7666732bb8a01958ab134db35bb792e7442a40e55ff1e7", size = 2049297, upload-time = "2026-01-09T15:58:39.184Z" }, - { url = "https://files.pythonhosted.org/packages/7a/d1/5ce55ef724aed0915edc877b6dd610d39b3169e4341154bb53daa022065a/outlines_core-0.2.14-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:66e695b375b180725fb534d9adf298531c152ec3d881e3b9e01c82b5dd269f52", size = 2200944, upload-time = "2026-01-09T15:58:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/32/e3/60ad781251eedcf1496317ecd58eb2e4488717ba63b10494ab49dfd05e5d/outlines_core-0.2.14-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:6bd166d3b07acef2f60d4ede44592a26d3f7d8712876bfc8e22150045def5857", size = 2049607, upload-time = "2026-01-09T15:58:41.635Z" }, - { url = "https://files.pythonhosted.org/packages/bc/2d/662d6a76face5b4b3481f888900d00856c37aa2927341a023866457da212/outlines_core-0.2.14-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:9d45462d7548aa0e17176a691ae73447f3e6bed9658a0cd96fe72eadf7474475", size = 2197755, upload-time = "2026-01-09T15:58:42.861Z" }, { url = "https://files.pythonhosted.org/packages/c1/9a/4b62903de006d991b58674ff033c1b6fb92be5767360376fc961f6771bdb/outlines_core-0.2.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6453e23f01d98ec48e3a4141d7112792ce77001dfb28d91d6fd89f47009f91ef", size = 2341051, upload-time = "2026-01-09T15:58:44.415Z" }, { url = "https://files.pythonhosted.org/packages/50/36/1532f7d9ab16c676812d94528e89964aa0d15f12adcb285e6ed86f86f2fe/outlines_core-0.2.14-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7deef6df74cb247f2a3a62f03438ba967456504b0555ec7029f8db834e054448", size = 2236778, upload-time = "2026-01-09T15:58:45.437Z" }, - { url = "https://files.pythonhosted.org/packages/a8/5a/dfd94f15f4c04e691e7fdf30cf8b9b22bf2cbc426b3ef270af3e200596d5/outlines_core-0.2.14-cp313-cp313-win32.whl", hash = "sha256:bb008c7ecc034bcfda0ddc10a4d1f2181a4b61ec1643ee56183dd6fa64139c9d", size = 1842727, upload-time = "2026-01-09T15:58:46.723Z" }, - { url = "https://files.pythonhosted.org/packages/34/35/e24ab5d2116812464380587435297d8ece2f0218c2ba8afc9f541e3a6911/outlines_core-0.2.14-cp313-cp313-win_amd64.whl", hash = "sha256:eb27e92204b296a063ac58f361153be4e78c8103a96e0b1c085b22d4fc3534cf", size = 2137108, upload-time = "2026-01-09T15:58:47.784Z" }, ] [[package]] @@ -5082,15 +4601,10 @@ dependencies = [ ] 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/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" }, @@ -5166,28 +4680,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" }, { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" }, { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" }, - { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" }, - { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" }, { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" }, { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" }, { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" }, { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" }, { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" }, { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" }, - { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" }, - { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" }, - { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" }, - { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" }, - { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" }, { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" }, { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" }, { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" }, { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" }, { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" }, { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" }, - { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, - { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, ] [[package]] @@ -5307,40 +4811,14 @@ version = "0.5.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/09/f049e45385503fe67db75a6b6186a7b9f0c3930366dc960522c312a825b1/propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a", size = 94457, upload-time = "2026-05-08T21:00:36.355Z" }, - { url = "https://files.pythonhosted.org/packages/6b/65/83d1d05655baf63113731bd5a1008435e14f8d1e5a06cbe4ec5b23ad7a31/propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117", size = 53835, upload-time = "2026-05-08T21:00:38.072Z" }, - { url = "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098", size = 54545, upload-time = "2026-05-08T21:00:39.319Z" }, { url = "https://files.pythonhosted.org/packages/a9/19/7fa086f5764c59ec8a8e157cd93aa8497acc00aba9dcdec56bfffb32602d/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4", size = 59886, upload-time = "2026-05-08T21:00:40.621Z" }, - { url = "https://files.pythonhosted.org/packages/a1/e4/5d7663dc8235956c8f5281698a3af1d351d8820341ddd890f59d9a9127f2/propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e", size = 63261, upload-time = "2026-05-08T21:00:41.775Z" }, - { url = "https://files.pythonhosted.org/packages/4a/4a/15a03adee24d6350da4292caeac44c34c033d2afe5e87eb370f38854560f/propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7", size = 64184, upload-time = "2026-05-08T21:00:43.018Z" }, { url = "https://files.pythonhosted.org/packages/8b/c6/979176efdaa3d239e36d503d5af63a0a773b36662ed8f52e5b6a6d9fd40e/propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d", size = 61534, upload-time = "2026-05-08T21:00:44.507Z" }, - { url = "https://files.pythonhosted.org/packages/c8/22/63e8cd1bae4c2d2be6493b6b7d10566ddafad88137cfbc99964a1119853c/propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a", size = 61500, upload-time = "2026-05-08T21:00:45.796Z" }, { url = "https://files.pythonhosted.org/packages/60/5a/28e5d9acbac1cc9ccb67045e8c1b943aa8d79fdf39c93bd73cacd68008ea/propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2", size = 59994, upload-time = "2026-05-08T21:00:47.093Z" }, - { url = "https://files.pythonhosted.org/packages/f3/40/db650677f554a95b9c01a7c9d93d629e93a15562f5deb4573c9ee136fed2/propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa", size = 56884, upload-time = "2026-05-08T21:00:48.376Z" }, - { url = "https://files.pythonhosted.org/packages/80/45/70b39b89516ff8b96bf732fa6fded8cef20f293cb1508690101c3c07ec51/propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853", size = 63464, upload-time = "2026-05-08T21:00:49.954Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e2/fa59d3a89eac5534293124af4f1d0d0ada091ce4a0ab4610ce03fd2bdd8d/propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a", size = 61588, upload-time = "2026-05-08T21:00:51.281Z" }, - { url = "https://files.pythonhosted.org/packages/0b/97/efb547a55c4bc7381cfb202d6a2239ac621045277bc1ea5dfd3a7f0516c0/propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704", size = 64667, upload-time = "2026-05-08T21:00:52.602Z" }, { url = "https://files.pythonhosted.org/packages/92/56/f5c7d9b4b7595d5127da38974d791b2153f3d1eae6c674af3583ace92ad3/propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4", size = 62463, upload-time = "2026-05-08T21:00:54.303Z" }, - { url = "https://files.pythonhosted.org/packages/bd/3b/484a3a65fc9f9f60c41dcd17b428bace5389544e2c680994534a20755066/propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d", size = 38621, upload-time = "2026-05-08T21:00:55.808Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fd/3f0f10dba4dabad3bf53102be007abf55481067952bde0fdddff439e7c61/propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757", size = 41649, upload-time = "2026-05-08T21:00:57.061Z" }, - { url = "https://files.pythonhosted.org/packages/90/ec/6ce619cc32bb500a482f811f9cd509368b4e58e638d13f2c68f370d6b475/propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f", size = 37636, upload-time = "2026-05-08T21:00:58.646Z" }, - { url = "https://files.pythonhosted.org/packages/1b/82/c1d268bbbf2ef981c5bf0fbbe746db617c66e3bcefe431a1aa8943fbe23a/propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d", size = 98872, upload-time = "2026-05-08T21:00:59.889Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d4/52c871e73e864e6b34c0e2d58ac1ec5ccd149497ddc7ad2137ae98323a35/propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa", size = 56257, upload-time = "2026-05-08T21:01:01.195Z" }, - { url = "https://files.pythonhosted.org/packages/67/f0/9b90ca2a210b3d09bcfcd96ecd0f55545c091535abce2a45de2775cfd357/propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94", size = 56696, upload-time = "2026-05-08T21:01:02.941Z" }, { url = "https://files.pythonhosted.org/packages/9d/0e/6e9d4ba07c8e56e21ddec1e75f12148142b21ca83a51871babce095334f4/propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164", size = 62378, upload-time = "2026-05-08T21:01:04.475Z" }, - { url = "https://files.pythonhosted.org/packages/65/19/c10badaa463dde8a27ce884f8ee2ec37e6035b7c9f5ff0c8f74f06f08dac/propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f", size = 65283, upload-time = "2026-05-08T21:01:05.959Z" }, - { url = "https://files.pythonhosted.org/packages/b0/b6/93bea99ca80e19cef6512a8580e5b7857bbe09422d9daa7fd4ef5723306c/propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c", size = 66616, upload-time = "2026-05-08T21:01:07.228Z" }, { url = "https://files.pythonhosted.org/packages/83/e4/5c7462e50625f051f37fb38b8224f7639f667184bbd34424ec83819bb1b7/propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc", size = 63773, upload-time = "2026-05-08T21:01:08.514Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b6/99238894047b13c823be25027e736626cd414a52a5e30d2c3347c2733529/propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f", size = 63664, upload-time = "2026-05-08T21:01:09.874Z" }, { url = "https://files.pythonhosted.org/packages/85/1e/a3a1a63116a2b8edb415a8bb9a6f0c34bd03830b1e18e8ce2904e1dc1cf4/propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb", size = 62643, upload-time = "2026-05-08T21:01:11.132Z" }, - { url = "https://files.pythonhosted.org/packages/e4/03/893cf147de2fc6543c5eaa07ad833170e7e2a2385725bbebe8c0503723bb/propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751", size = 59595, upload-time = "2026-05-08T21:01:12.387Z" }, - { url = "https://files.pythonhosted.org/packages/86/3b/04c1a2e12c57766568ba75ba72b3bf2042818d4c1425fab6fc07155c7cff/propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836", size = 65711, upload-time = "2026-05-08T21:01:13.676Z" }, - { url = "https://files.pythonhosted.org/packages/1c/34/80f8d0099f8d6bacc4de1624c85672681c8cd1149ca2da0e38fd120b817f/propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f", size = 64247, upload-time = "2026-05-08T21:01:14.936Z" }, - { url = "https://files.pythonhosted.org/packages/f3/1a/8b08f3a5f1037e9e370c55883ceeeee0f6dd0416fb2d2d67b8bfc91f2a79/propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55", size = 67102, upload-time = "2026-05-08T21:01:16.281Z" }, { url = "https://files.pythonhosted.org/packages/34/68/8bdb7bb7756d76e005490649d10e4a8369e610c74d619f71e1aedf889e9c/propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568", size = 64964, upload-time = "2026-05-08T21:01:17.57Z" }, - { url = "https://files.pythonhosted.org/packages/0a/aa/50fb0b5d3968b61a510926ff8b8465f1d6e976b3ab74496d7a4b9fc42515/propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191", size = 42546, upload-time = "2026-05-08T21:01:18.946Z" }, - { url = "https://files.pythonhosted.org/packages/ae/4c/0ddbae64321bd4a95bcbfc19307238016b5b1fee645c84626c8d539e5b74/propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7", size = 46330, upload-time = "2026-05-08T21:01:20.162Z" }, - { url = "https://files.pythonhosted.org/packages/00/d9/9cddc8efb78d8af264c5ec9f6d10b62f57c515feda8d321595f56010fb23/propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96", size = 40521, upload-time = "2026-05-08T21:01:21.399Z" }, { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, ] @@ -5362,11 +4840,7 @@ version = "6.33.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, - { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, - { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, ] @@ -5377,20 +4851,12 @@ 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]] @@ -5435,13 +4901,8 @@ version = "0.4.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/93/d8/5b71371f50cf153b1307e5a11ac8a4ce4d85651dae946bd7e9a064146545/py_spy-0.4.2.tar.gz", hash = "sha256:90e600b27bb6bb40479637baca5a5b4bc2ba3395c93d889e672315d93042c4ae", size = 286374, upload-time = "2026-04-24T22:08:54.906Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/21/ec030145a0c7992bd4b9eafb2f06f56358b3a5339eab4a16534baf3c69aa/py_spy-0.4.2-py2.py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:1ccf688393105111684435f035bc14ec3f22117dd2b85b2414612cf27a22755a", size = 3743992, upload-time = "2026-04-24T22:08:45.438Z" }, - { url = "https://files.pythonhosted.org/packages/50/80/de5fd27243c2be03692ecd317bf0dbe24b4c6f78f689ce111e7277a7cb09/py_spy-0.4.2-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:a0e6f6810ccf0fc5e64e85e0182a5b626c4496eec01b14fb8755154b363a4831", size = 1859057, upload-time = "2026-04-24T22:08:46.946Z" }, { url = "https://files.pythonhosted.org/packages/89/23/3eb4c23c684ebd667674ce1d076ae855e0621d1d9bd5e052aa3f7982f757/py_spy-0.4.2-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:142887e984a4e541071c99a4401ff8c3770f255d329dbd0f64e8c1dd51882cce", size = 2828136, upload-time = "2026-04-24T22:08:48.519Z" }, - { url = "https://files.pythonhosted.org/packages/ca/01/6314152cf9ad3310ebacbf2c47b5ed858086530f8e12b1a665725ca5e0f4/py_spy-0.4.2-py2.py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1c6d9b0e2379ead5bf792df43f4cf36153aa79e6dda4fb8ac7740cf8017110", size = 2857707, upload-time = "2026-04-24T22:08:49.677Z" }, - { url = "https://files.pythonhosted.org/packages/cc/1f/0960a129d504728d28a51dbd5a04ce94031eb75bac676341da7aefdd8232/py_spy-0.4.2-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24720573f95230653b457671a1dcc3c5a381fcf4e92677761e328a430ad251b2", size = 2301852, upload-time = "2026-04-24T22:08:51.152Z" }, { url = "https://files.pythonhosted.org/packages/f9/34/dd7d3c763a00b7b965e25a5eab0acd1a345dbaf0f45fffe595278873a1c0/py_spy-0.4.2-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:aeb0323409199c785f730645e9f4bb7a7b9ca2c481f2c331a55642b5d13fa52f", size = 2936518, upload-time = "2026-04-24T22:08:52.264Z" }, - { url = "https://files.pythonhosted.org/packages/6f/ed/1409cdb557e558a6c98003ab12fdd4284699e158c167c187cb0f124eea4c/py_spy-0.4.2-py2.py3-none-win_amd64.whl", hash = "sha256:8b06a353c177677e4e1701b288d8c58e2f8d4208ee81a8048d9f72ba800918f8", size = 1894002, upload-time = "2026-04-24T22:08:53.811Z" }, ] [[package]] @@ -5450,20 +4911,14 @@ 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/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]] @@ -5493,49 +4948,17 @@ version = "1.4.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/aa/b8/4ed5c7ad5ec15b08d35cc79ace6145d5c1ae426e46435f4987379439dfea/pybase64-1.4.3.tar.gz", hash = "sha256:c2ed274c9e0ba9c8f9c4083cfe265e66dd679126cd9c2027965d807352f3f053", size = 137272, upload-time = "2025-12-06T13:27:04.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/50/b7170cb2c631944388fe2519507fe3835a4054a6a12a43f43781dae82be1/pybase64-1.4.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:ea4b785b0607d11950b66ce7c328f452614aefc9c6d3c9c28bae795dc7f072e1", size = 33901, upload-time = "2025-12-06T13:23:40.951Z" }, - { url = "https://files.pythonhosted.org/packages/48/8b/69f50578e49c25e0a26e3ee72c39884ff56363344b79fc3967f5af420ed6/pybase64-1.4.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:6a10b6330188c3026a8b9c10e6b9b3f2e445779cf16a4c453d51a072241c65a2", size = 40807, upload-time = "2025-12-06T13:23:42.006Z" }, { url = "https://files.pythonhosted.org/packages/5c/8d/20b68f11adfc4c22230e034b65c71392e3e338b413bf713c8945bd2ccfb3/pybase64-1.4.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:27fdff227a0c0e182e0ba37a99109645188978b920dfb20d8b9c17eeee370d0d", size = 30932, upload-time = "2025-12-06T13:23:43.348Z" }, { url = "https://files.pythonhosted.org/packages/f7/79/b1b550ac6bff51a4880bf6e089008b2e1ca16f2c98db5e039a08ac3ad157/pybase64-1.4.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2a8204f1fdfec5aa4184249b51296c0de95445869920c88123978304aad42df1", size = 31394, upload-time = "2025-12-06T13:23:44.317Z" }, { url = "https://files.pythonhosted.org/packages/82/70/b5d7c5932bf64ee1ec5da859fbac981930b6a55d432a603986c7f509c838/pybase64-1.4.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:874fc2a3777de6baf6aa921a7aa73b3be98295794bea31bd80568a963be30767", size = 38078, upload-time = "2025-12-06T13:23:45.348Z" }, - { url = "https://files.pythonhosted.org/packages/56/fe/e66fe373bce717c6858427670736d54297938dad61c5907517ab4106bd90/pybase64-1.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2dc64a94a9d936b8e3449c66afabbaa521d3cc1a563d6bbaaa6ffa4535222e4b", size = 38158, upload-time = "2025-12-06T13:23:46.872Z" }, - { url = "https://files.pythonhosted.org/packages/80/a9/b806ed1dcc7aed2ea3dd4952286319e6f3a8b48615c8118f453948e01999/pybase64-1.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e48f86de1c145116ccf369a6e11720ce696c2ec02d285f440dfb57ceaa0a6cb4", size = 31672, upload-time = "2025-12-06T13:23:47.88Z" }, - { url = "https://files.pythonhosted.org/packages/1c/c9/24b3b905cf75e23a9a4deaf203b35ffcb9f473ac0e6d8257f91a05dfce62/pybase64-1.4.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:1d45c8fe8fe82b65c36b227bb4a2cf623d9ada16bed602ce2d3e18c35285b72a", size = 68244, upload-time = "2025-12-06T13:23:49.026Z" }, { url = "https://files.pythonhosted.org/packages/f8/cd/d15b0c3e25e5859fab0416dc5b96d34d6bd2603c1c96a07bb2202b68ab92/pybase64-1.4.3-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ad70c26ba091d8f5167e9d4e1e86a0483a5414805cdb598a813db635bd3be8b8", size = 71620, upload-time = "2025-12-06T13:23:50.081Z" }, { url = "https://files.pythonhosted.org/packages/0d/31/4ca953cc3dcde2b3711d6bfd70a6f4ad2ca95a483c9698076ba605f1520f/pybase64-1.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e98310b7c43145221e7194ac9fa7fffc84763c87bfc5e2f59f9f92363475bdc1", size = 59930, upload-time = "2025-12-06T13:23:51.68Z" }, - { url = "https://files.pythonhosted.org/packages/60/55/e7f7bdcd0fd66e61dda08db158ffda5c89a306bbdaaf5a062fbe4e48f4a1/pybase64-1.4.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:398685a76034e91485a28aeebcb49e64cd663212fd697b2497ac6dfc1df5e671", size = 56425, upload-time = "2025-12-06T13:23:52.732Z" }, - { url = "https://files.pythonhosted.org/packages/cb/65/b592c7f921e51ca1aca3af5b0d201a98666d0a36b930ebb67e7c2ed27395/pybase64-1.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7e46400a6461187ccb52ed75b0045d937529e801a53a9cd770b350509f9e4d50", size = 59327, upload-time = "2025-12-06T13:23:53.856Z" }, - { url = "https://files.pythonhosted.org/packages/23/95/1613d2fb82dbb1548595ad4179f04e9a8451bfa18635efce18b631eabe3f/pybase64-1.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1b62b9f2f291d94f5e0b76ab499790b7dcc78a009d4ceea0b0428770267484b6", size = 60294, upload-time = "2025-12-06T13:23:54.937Z" }, - { url = "https://files.pythonhosted.org/packages/9d/73/40431f37f7d1b3eab4673e7946ff1e8f5d6bd425ec257e834dae8a6fc7b0/pybase64-1.4.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:f30ceb5fa4327809dede614be586efcbc55404406d71e1f902a6fdcf322b93b2", size = 54858, upload-time = "2025-12-06T13:23:56.031Z" }, { url = "https://files.pythonhosted.org/packages/a7/84/f6368bcaf9f743732e002a9858646fd7a54f428490d427dd6847c5cfe89e/pybase64-1.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0d5f18ed53dfa1d4cf8b39ee542fdda8e66d365940e11f1710989b3cf4a2ed66", size = 58629, upload-time = "2025-12-06T13:23:57.12Z" }, - { url = "https://files.pythonhosted.org/packages/43/75/359532f9adb49c6b546cafc65c46ed75e2ccc220d514ba81c686fbd83965/pybase64-1.4.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:119d31aa4b58b85a8ebd12b63c07681a138c08dfc2fe5383459d42238665d3eb", size = 52448, upload-time = "2025-12-06T13:23:58.298Z" }, - { url = "https://files.pythonhosted.org/packages/92/6c/ade2ba244c3f33ed920a7ed572ad772eb0b5f14480b72d629d0c9e739a40/pybase64-1.4.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3cf0218b0e2f7988cf7d738a73b6a1d14f3be6ce249d7c0f606e768366df2cce", size = 68841, upload-time = "2025-12-06T13:23:59.886Z" }, - { url = "https://files.pythonhosted.org/packages/a0/51/b345139cd236be382f2d4d4453c21ee6299e14d2f759b668e23080f8663f/pybase64-1.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:12f4ee5e988bc5c0c1106b0d8fc37fb0508f12dab76bac1b098cb500d148da9d", size = 57910, upload-time = "2025-12-06T13:24:00.994Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b8/9f84bdc4f1c4f0052489396403c04be2f9266a66b70c776001eaf0d78c1f/pybase64-1.4.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:937826bc7b6b95b594a45180e81dd4d99bd4dd4814a443170e399163f7ff3fb6", size = 54335, upload-time = "2025-12-06T13:24:02.046Z" }, - { url = "https://files.pythonhosted.org/packages/d0/c7/be63b617d284de46578a366da77ede39c8f8e815ed0d82c7c2acca560fab/pybase64-1.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:88995d1460971ef80b13e3e007afbe4b27c62db0508bc7250a2ab0a0b4b91362", size = 56486, upload-time = "2025-12-06T13:24:03.141Z" }, { url = "https://files.pythonhosted.org/packages/5e/96/f252c8f9abd6ded3ef1ccd3cdbb8393a33798007f761b23df8de1a2480e6/pybase64-1.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:72326fe163385ed3e1e806dd579d47fde5d8a59e51297a60fc4e6cbc1b4fc4ed", size = 70978, upload-time = "2025-12-06T13:24:04.221Z" }, - { url = "https://files.pythonhosted.org/packages/af/51/0f5714af7aeef96e30f968e4371d75ad60558aaed3579d7c6c8f1c43c18a/pybase64-1.4.3-cp313-cp313-win32.whl", hash = "sha256:b1623730c7892cf5ed0d6355e375416be6ef8d53ab9b284f50890443175c0ac3", size = 33684, upload-time = "2025-12-06T13:24:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/b6/ad/0cea830a654eb08563fb8214150ef57546ece1cc421c09035f0e6b0b5ea9/pybase64-1.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:8369887590f1646a5182ca2fb29252509da7ae31d4923dbb55d3e09da8cc4749", size = 35832, upload-time = "2025-12-06T13:24:06.35Z" }, - { url = "https://files.pythonhosted.org/packages/b4/0d/eec2a8214989c751bc7b4cad1860eb2c6abf466e76b77508c0f488c96a37/pybase64-1.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:860b86bca71e5f0237e2ab8b2d9c4c56681f3513b1bf3e2117290c1963488390", size = 31175, upload-time = "2025-12-06T13:24:07.419Z" }, - { url = "https://files.pythonhosted.org/packages/db/c9/e23463c1a2913686803ef76b1a5ae7e6fac868249a66e48253d17ad7232c/pybase64-1.4.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eb51db4a9c93215135dccd1895dca078e8785c357fabd983c9f9a769f08989a9", size = 38497, upload-time = "2025-12-06T13:24:08.873Z" }, - { url = "https://files.pythonhosted.org/packages/71/83/343f446b4b7a7579bf6937d2d013d82f1a63057cf05558e391ab6039d7db/pybase64-1.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a03ef3f529d85fd46b89971dfb00c634d53598d20ad8908fb7482955c710329d", size = 32076, upload-time = "2025-12-06T13:24:09.975Z" }, - { url = "https://files.pythonhosted.org/packages/46/fc/cb64964c3b29b432f54d1bce5e7691d693e33bbf780555151969ffd95178/pybase64-1.4.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2e745f2ce760c6cf04d8a72198ef892015ddb89f6ceba489e383518ecbdb13ab", size = 72317, upload-time = "2025-12-06T13:24:11.129Z" }, { url = "https://files.pythonhosted.org/packages/0a/b7/fab2240da6f4e1ad46f71fa56ec577613cf5df9dce2d5b4cfaa4edd0e365/pybase64-1.4.3-cp313-cp313t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fac217cd9de8581a854b0ac734c50fd1fa4b8d912396c1fc2fce7c230efe3a7", size = 75534, upload-time = "2025-12-06T13:24:12.433Z" }, { url = "https://files.pythonhosted.org/packages/91/3b/3e2f2b6e68e3d83ddb9fa799f3548fb7449765daec9bbd005a9fbe296d7f/pybase64-1.4.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:da1ee8fa04b283873de2d6e8fa5653e827f55b86bdf1a929c5367aaeb8d26f8a", size = 65399, upload-time = "2025-12-06T13:24:13.928Z" }, - { url = "https://files.pythonhosted.org/packages/6b/08/476ac5914c3b32e0274a2524fc74f01cbf4f4af4513d054e41574eb018f6/pybase64-1.4.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:b0bf8e884ee822ca7b1448eeb97fa131628fe0ff42f60cae9962789bd562727f", size = 60487, upload-time = "2025-12-06T13:24:15.177Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b8/618a92915330cc9cba7880299b546a1d9dab1a21fd6c0292ee44a4fe608c/pybase64-1.4.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1bf749300382a6fd1f4f255b183146ef58f8e9cb2f44a077b3a9200dfb473a77", size = 63959, upload-time = "2025-12-06T13:24:16.854Z" }, - { url = "https://files.pythonhosted.org/packages/a5/52/af9d8d051652c3051862c442ec3861259c5cdb3fc69774bc701470bd2a59/pybase64-1.4.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:153a0e42329b92337664cfc356f2065248e6c9a1bd651bbcd6dcaf15145d3f06", size = 64874, upload-time = "2025-12-06T13:24:18.328Z" }, - { url = "https://files.pythonhosted.org/packages/e4/51/5381a7adf1f381bd184d33203692d3c57cf8ae9f250f380c3fecbdbe554b/pybase64-1.4.3-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:86ee56ac7f2184ca10217ed1c655c1a060273e233e692e9086da29d1ae1768db", size = 58572, upload-time = "2025-12-06T13:24:19.417Z" }, { url = "https://files.pythonhosted.org/packages/e0/f0/578ee4ffce5818017de4fdf544e066c225bc435e73eb4793cde28a689d0b/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0e71a4db76726bf830b47477e7d830a75c01b2e9b01842e787a0836b0ba741e3", size = 63636, upload-time = "2025-12-06T13:24:20.497Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ad/8ae94814bf20159ea06310b742433e53d5820aa564c9fdf65bf2d79f8799/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2ba7799ec88540acd9861b10551d24656ca3c2888ecf4dba2ee0a71544a8923f", size = 56193, upload-time = "2025-12-06T13:24:21.559Z" }, - { url = "https://files.pythonhosted.org/packages/d1/31/6438cfcc3d3f0fa84d229fa125c243d5094e72628e525dfefadf3bcc6761/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2860299e4c74315f5951f0cf3e72ba0f201c3356c8a68f95a3ab4e620baf44e9", size = 72655, upload-time = "2025-12-06T13:24:22.673Z" }, - { url = "https://files.pythonhosted.org/packages/a3/0d/2bbc9e9c3fc12ba8a6e261482f03a544aca524f92eae0b4908c0a10ba481/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:bb06015db9151f0c66c10aae8e3603adab6b6cd7d1f7335a858161d92fc29618", size = 62471, upload-time = "2025-12-06T13:24:23.8Z" }, - { url = "https://files.pythonhosted.org/packages/2c/0b/34d491e7f49c1dbdb322ea8da6adecda7c7cd70b6644557c6e4ca5c6f7c7/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:242512a070817272865d37c8909059f43003b81da31f616bb0c391ceadffe067", size = 58119, upload-time = "2025-12-06T13:24:24.994Z" }, - { url = "https://files.pythonhosted.org/packages/ce/17/c21d0cde2a6c766923ae388fc1f78291e1564b0d38c814b5ea8a0e5e081c/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5d8277554a12d3e3eed6180ebda62786bf9fc8d7bb1ee00244258f4a87ca8d20", size = 60791, upload-time = "2025-12-06T13:24:26.046Z" }, { url = "https://files.pythonhosted.org/packages/92/b2/eaa67038916a48de12b16f4c384bcc1b84b7ec731b23613cb05f27673294/pybase64-1.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f40b7ddd698fc1e13a4b64fbe405e4e0e1279e8197e37050e24154655f5f7c4e", size = 74701, upload-time = "2025-12-06T13:24:27.466Z" }, - { url = "https://files.pythonhosted.org/packages/42/10/abb7757c330bb869ebb95dab0c57edf5961ffbd6c095c8209cbbf75d117d/pybase64-1.4.3-cp313-cp313t-win32.whl", hash = "sha256:46d75c9387f354c5172582a9eaae153b53a53afeb9c19fcf764ea7038be3bd8b", size = 33965, upload-time = "2025-12-06T13:24:28.548Z" }, - { url = "https://files.pythonhosted.org/packages/63/a0/2d4e5a59188e9e6aed0903d580541aaea72dcbbab7bf50fb8b83b490b6c3/pybase64-1.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:d7344625591d281bec54e85cbfdab9e970f6219cac1570f2aa140b8c942ccb81", size = 36207, upload-time = "2025-12-06T13:24:29.646Z" }, - { url = "https://files.pythonhosted.org/packages/1f/05/95b902e8f567b4d4b41df768ccc438af618f8d111e54deaf57d2df46bd76/pybase64-1.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:28a3c60c55138e0028313f2eccd321fec3c4a0be75e57a8d3eb883730b1b0880", size = 31505, upload-time = "2025-12-06T13:24:30.687Z" }, ] [[package]] @@ -5571,28 +4994,14 @@ version = "3.23.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, - { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, - { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, - { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, - { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, - { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, - { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, - { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, - { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, - { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, - { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, - { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, - { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, ] [[package]] @@ -5624,21 +5033,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, - { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, - { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, - { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, - { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, - { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, - { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, - { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, - { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, ] [[package]] @@ -5764,14 +5162,8 @@ version = "0.24.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/26/c3/17be94de732d01d86a671eb1e93608000a0594e60d05a14c5d9f13dbe21d/pyrefly-0.24.2.tar.gz", hash = "sha256:671b9933c2a3f646983de68bc0422736f7ce364c4f645f742559423b0b9b5150", size = 1129442, upload-time = "2025-07-15T02:40:19.25Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/cd/07862f0afd79e215617494495510d06cb7cc5907f5f32594498e7bb64f7e/pyrefly-0.24.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7e6bd1b88ec53b3f1ce2ece844016d7e7f0848a77022857a7fa6674a49abcc13", size = 6049599, upload-time = "2025-07-15T02:40:03.363Z" }, - { url = "https://files.pythonhosted.org/packages/b7/ce/680ce3c12a9d8cf0312207d1eee31947e5ceae169680fe2e341718f299be/pyrefly-0.24.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:83aa9013f2299dfc8ce11adec30a63be71528484c45e603375efe7496cb0538e", size = 5634851, upload-time = "2025-07-15T02:40:05.742Z" }, { url = "https://files.pythonhosted.org/packages/0f/12/3846ceefaeccb6209b4bcb3518143039effbe7f16f864377949b78952814/pyrefly-0.24.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bf1689032b78f8f653244cd323ee1e06a0efb6192c4d7a415d1e85aedd37905", size = 5852019, upload-time = "2025-07-15T02:40:07.69Z" }, - { url = "https://files.pythonhosted.org/packages/a0/a3/cab8503091f244aa243995cb8745842198d71eb71225abe9ba8a1de78024/pyrefly-0.24.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8404b804a5a1bc4a54cc8e58bceacdf49d7221531843c068547241d8f476af24", size = 6546257, upload-time = "2025-07-15T02:40:09.729Z" }, { url = "https://files.pythonhosted.org/packages/e0/06/b2881239f4a22c800003feaa3e653d6f635ea8979db506545e3c43bbf606/pyrefly-0.24.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d09f166a46e43655ea812611887ca16a0c54386296f4c9333f3f5fc7236709", size = 6296266, upload-time = "2025-07-15T02:40:11.667Z" }, - { url = "https://files.pythonhosted.org/packages/66/39/c414c1a30c24badb5153dd2d1ddb974d5b5662f80be9f1fed626fcfe6479/pyrefly-0.24.2-py3-none-win32.whl", hash = "sha256:6c602df48dcfa3240f9076c7d1e9cf9dc2d94c90ee5b4c6745f3734125a2cf3a", size = 5833755, upload-time = "2025-07-15T02:40:13.539Z" }, - { url = "https://files.pythonhosted.org/packages/0d/2b/36d211dd03b86cb6216968f64081437837507debe30f58834a97091eda83/pyrefly-0.24.2-py3-none-win_amd64.whl", hash = "sha256:9ed4690716eb47077082d4e99624e0a1165b9ac93300c8d823f42cae12ec1ef4", size = 6207616, upload-time = "2025-07-15T02:40:15.188Z" }, - { url = "https://files.pythonhosted.org/packages/af/9a/d51db168fe6bdae00b813582287d251e116666f07cb388b62d1715808891/pyrefly-0.24.2-py3-none-win_arm64.whl", hash = "sha256:96ba49c02f374d716b8674409aa653093dad5263cf4e429a1d5ec603064db715", size = 5867507, upload-time = "2025-07-15T02:40:16.793Z" }, ] [[package]] @@ -5984,16 +5376,10 @@ 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/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]] @@ -6005,28 +5391,14 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, - { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, - { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, - { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, - { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, - { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, ] [[package]] @@ -6095,7 +5467,6 @@ dependencies = [ { name = "requests", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/95/898699cc1a6a5f304ea95376d079843b5c05f4c8c1ec7e55a5cc7ffcea50/ray-2.55.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:f9844a9272ef2e6eb5771025866072cf4234cf4c7cc1a31e235b7de7111864be", size = 65766823, upload-time = "2026-04-22T20:10:20.786Z" }, { url = "https://files.pythonhosted.org/packages/c9/13/87deecc090c672e45a0cf6f5eef511de448b93f37ef18fd10eb8e8557a0d/ray-2.55.1-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:b415d590e062f248907e0fe42994943f11726b7178fcf4b1cf5546721fb1a5f8", size = 72818676, upload-time = "2026-04-22T20:10:26.705Z" }, { url = "https://files.pythonhosted.org/packages/71/d7/fc95d3b8824c62105c64aa1b59c59600b581f608d78a2af753e010936dc9/ray-2.55.1-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:1380e043eb57cde69b7e9199c6f2558ceeb8f0fc41c97d1d5e50ea042115f302", size = 73678908, upload-time = "2026-04-22T20:10:32.795Z" }, ] @@ -6137,38 +5508,14 @@ version = "2026.5.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/da/797e91ecec6f84135da778ddce78c20e0af5d2a15c26f87a81bc3eadb6db/regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb", size = 490303, upload-time = "2026-05-09T23:13:04.382Z" }, - { url = "https://files.pythonhosted.org/packages/44/da/bf30abaaa737b58f4a4b8c4a03659e02fd92092c822e0197ed9e0daab917/regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f", size = 292019, upload-time = "2026-05-09T23:13:06.022Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e7/d0eaf5713828417b9e5648cf81fa9bacd4961f6ab98c380c2034f8716e35/regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c", size = 289468, upload-time = "2026-05-09T23:13:08.214Z" }, { url = "https://files.pythonhosted.org/packages/d3/9b/b3fdd62b003baa1a9b593cd8c8699c9651c2e80cc21a5c715707983c42d7/regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed", size = 796749, upload-time = "2026-05-09T23:13:10.573Z" }, - { url = "https://files.pythonhosted.org/packages/d4/30/66ab84588765f5b4b271a9ca09ef7ce2b87caa95176ec3d2ad65d7bc4902/regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020", size = 865445, upload-time = "2026-05-09T23:13:12.523Z" }, - { url = "https://files.pythonhosted.org/packages/1a/89/f05169e8588aac365f35ffc7f3bc3184f095ef4cfded7cfaa3c7fd5dbd89/regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2", size = 912322, upload-time = "2026-05-09T23:13:14.281Z" }, { url = "https://files.pythonhosted.org/packages/30/e1/c93444052cf41581f3c884ab3fb5823daf0992f11cd4388d4275ca610558/regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2", size = 801269, upload-time = "2026-05-09T23:13:16.569Z" }, - { url = "https://files.pythonhosted.org/packages/50/fe/0cf96b882f540e62e8b9956599798203d599c44cf4c77917ca27400ff69b/regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04", size = 777085, upload-time = "2026-05-09T23:13:18.675Z" }, { url = "https://files.pythonhosted.org/packages/23/5c/d78d4924e7fc875557b9e9b768423925fdfaac5549d06da7810019a9bd26/regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c", size = 785153, upload-time = "2026-05-09T23:13:20.525Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e0/5214774090e7b4524dcea3e3c4aa74141d43043f8beb49c1599db1c8b53a/regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f", size = 860164, upload-time = "2026-05-09T23:13:22.263Z" }, - { url = "https://files.pythonhosted.org/packages/6e/e1/4a57a83350319b1271f0d7a249b8672513ed928b237a741631270de6caea/regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8", size = 765731, upload-time = "2026-05-09T23:13:24.277Z" }, - { url = "https://files.pythonhosted.org/packages/12/f4/499e74a20c156fc75836ee04a72a38d1a063978f600937f9760467beb1b0/regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6", size = 852062, upload-time = "2026-05-09T23:13:26.125Z" }, { url = "https://files.pythonhosted.org/packages/5b/92/7eebc0d0a01e78629695f342ba17e0deaff8fb45e79cc0d7b98287da6e3e/regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21", size = 789577, upload-time = "2026-05-09T23:13:27.814Z" }, - { url = "https://files.pythonhosted.org/packages/05/a4/018e71f7d2ad48c1ebe6d3ae0026f9b7cb4802fd15c7cc02fdf724355102/regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127", size = 266691, upload-time = "2026-05-09T23:13:29.549Z" }, - { url = "https://files.pythonhosted.org/packages/e6/1d/861a93719fb9ee7dbfc3761b3797b7a3e112a5d42c6129459d2d741be9b5/regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca", size = 277747, upload-time = "2026-05-09T23:13:31.859Z" }, - { url = "https://files.pythonhosted.org/packages/d9/c6/0a2436ae4da1ba76e51cb98943c6838a9a721faa40ebe2dce07694ae34e3/regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6", size = 270500, upload-time = "2026-05-09T23:13:33.525Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e9/d21346f7b60ed58789371358ed66b09d00f832e1bd7c06e55d9da5679882/regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3", size = 494172, upload-time = "2026-05-09T23:13:35.935Z" }, - { url = "https://files.pythonhosted.org/packages/c4/43/fd1177a2032037c681baecdb3422ee4e1424aec4e4f470ef47793d325274/regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6", size = 293952, upload-time = "2026-05-09T23:13:38.307Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7d/9fbf919768368d3f8a4f6c692cf2aa61e482b2b81ec6a298ace4cbf02480/regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff", size = 292314, upload-time = "2026-05-09T23:13:40.353Z" }, { url = "https://files.pythonhosted.org/packages/e2/6c/e41bfeecb589716843e7c4df09ba46ff2a42961457afece19059d85caeef/regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88", size = 811681, upload-time = "2026-05-09T23:13:42.543Z" }, - { url = "https://files.pythonhosted.org/packages/87/83/a5c1c525fba0aa656e88ad0face0b1829788ef4c2fb6b26df58aa1151b84/regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178", size = 871135, upload-time = "2026-05-09T23:13:44.326Z" }, - { url = "https://files.pythonhosted.org/packages/18/d4/80882e799e440dd878b0979cbebf8fa4d54624a332c83037c7a701649e3f/regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100", size = 917265, upload-time = "2026-05-09T23:13:47.295Z" }, { url = "https://files.pythonhosted.org/packages/ae/ff/8db60211e2286e396aad7dc7725356c502bff0901ea05bd6cdc2e1a042b9/regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e", size = 816311, upload-time = "2026-05-09T23:13:49.885Z" }, - { url = "https://files.pythonhosted.org/packages/4c/47/742ef579c61730f8d268e5cf1f9ce0e37e2ea041ad0f5644724f2378e463/regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2", size = 785498, upload-time = "2026-05-09T23:13:52.25Z" }, { url = "https://files.pythonhosted.org/packages/7f/ab/cb0999802dcb0fb95b1ab005e8d4163d8afdd67efc2cb6b6630ac13f8cb1/regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b", size = 801348, upload-time = "2026-05-09T23:13:54.127Z" }, - { url = "https://files.pythonhosted.org/packages/7d/62/8ca59a24c55bc34d166eefaf3717bd77772f329fdbf984d86581e0a3571c/regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e", size = 866493, upload-time = "2026-05-09T23:13:56.067Z" }, - { url = "https://files.pythonhosted.org/packages/8d/3d/30f2ae62cef3278bb5bb821f467277a55fb73f01032cf85997e15e8289a8/regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041", size = 772811, upload-time = "2026-05-09T23:13:57.867Z" }, - { url = "https://files.pythonhosted.org/packages/d8/ae/7d2089bcd78ad0c0161bc684339df50032acb438a7bd3305e7ddb1193cec/regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0", size = 856584, upload-time = "2026-05-09T23:13:59.679Z" }, { url = "https://files.pythonhosted.org/packages/a9/29/92ff47f75990131ea4f24ba17819e5a9d141e10819807e09addd73409af6/regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081", size = 803453, upload-time = "2026-05-09T23:14:01.978Z" }, - { url = "https://files.pythonhosted.org/packages/04/99/eff29f1037dcab36702c9ee5d6858cf1ce2336ea8ea2987f64245b99ea5e/regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5", size = 269951, upload-time = "2026-05-09T23:14:03.661Z" }, - { url = "https://files.pythonhosted.org/packages/0e/9d/8870b8981d27b22cda77bb26a5ac7ebfa9c7d9e0dea195a834a82380e748/regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4", size = 281240, upload-time = "2026-05-09T23:14:05.56Z" }, - { url = "https://files.pythonhosted.org/packages/72/b1/3379415e8f135c13ac551353397cc4fe97b4978f3cac73c5fcbcded548b8/regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de", size = 272383, upload-time = "2026-05-09T23:14:07.843Z" }, ] [[package]] @@ -6243,21 +5590,10 @@ version = "0.7.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/8a/a4078f6e14932ac7edb171149c481de29969d96ddee3ece5dc4c26f9e0c3/rignore-0.7.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2bdab1d31ec9b4fb1331980ee49ea051c0d7f7bb6baa28b3125ef03cdc48fdaf", size = 883057, upload-time = "2025-11-05T20:42:42.741Z" }, - { url = "https://files.pythonhosted.org/packages/f9/8f/f8daacd177db4bf7c2223bab41e630c52711f8af9ed279be2058d2fe4982/rignore-0.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90f0a00ce0c866c275bf888271f1dc0d2140f29b82fcf33cdbda1e1a6af01010", size = 820150, upload-time = "2025-11-05T20:42:26.545Z" }, { url = "https://files.pythonhosted.org/packages/36/31/b65b837e39c3f7064c426754714ac633b66b8c2290978af9d7f513e14aa9/rignore-0.7.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ad295537041dc2ed4b540fb1a3906bd9ede6ccdad3fe79770cd89e04e3c73c", size = 897406, upload-time = "2025-11-05T20:40:53.854Z" }, - { url = "https://files.pythonhosted.org/packages/ca/58/1970ce006c427e202ac7c081435719a076c478f07b3a23f469227788dc23/rignore-0.7.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f782dbd3a65a5ac85adfff69e5c6b101285ef3f845c3a3cae56a54bebf9fe116", size = 874050, upload-time = "2025-11-05T20:41:08.922Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/eb45db9f90137329072a732273be0d383cb7d7f50ddc8e0bceea34c1dfdf/rignore-0.7.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65cece3b36e5b0826d946494734c0e6aaf5a0337e18ff55b071438efe13d559e", size = 1167835, upload-time = "2025-11-05T20:41:24.997Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f1/6f1d72ddca41a64eed569680587a1236633587cc9f78136477ae69e2c88a/rignore-0.7.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e4bb66c13cd7602dc8931822c02dfbbd5252015c750ac5d6152b186f0a8be0", size = 941945, upload-time = "2025-11-05T20:41:40.628Z" }, { url = "https://files.pythonhosted.org/packages/48/6f/2f178af1c1a276a065f563ec1e11e7a9e23d4996fd0465516afce4b5c636/rignore-0.7.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297e500c15766e196f68aaaa70e8b6db85fa23fdc075b880d8231fdfba738cd7", size = 959067, upload-time = "2025-11-05T20:42:11.09Z" }, - { url = "https://files.pythonhosted.org/packages/5b/db/423a81c4c1e173877c7f9b5767dcaf1ab50484a94f60a0b2ed78be3fa765/rignore-0.7.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a07084211a8d35e1a5b1d32b9661a5ed20669970b369df0cf77da3adea3405de", size = 984438, upload-time = "2025-11-05T20:41:55.443Z" }, { url = "https://files.pythonhosted.org/packages/31/eb/c4f92cc3f2825d501d3c46a244a671eb737fc1bcf7b05a3ecd34abb3e0d7/rignore-0.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:181eb2a975a22256a1441a9d2f15eb1292839ea3f05606620bd9e1938302cf79", size = 1078365, upload-time = "2025-11-05T21:40:15.148Z" }, - { url = "https://files.pythonhosted.org/packages/26/09/99442f02794bd7441bfc8ed1c7319e890449b816a7493b2db0e30af39095/rignore-0.7.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7bbcdc52b5bf9f054b34ce4af5269df5d863d9c2456243338bc193c28022bd7b", size = 1139066, upload-time = "2025-11-05T21:40:32.771Z" }, - { url = "https://files.pythonhosted.org/packages/2c/88/bcfc21e520bba975410e9419450f4b90a2ac8236b9a80fd8130e87d098af/rignore-0.7.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f2e027a6da21a7c8c0d87553c24ca5cc4364def18d146057862c23a96546238e", size = 1118036, upload-time = "2025-11-05T21:40:49.646Z" }, { url = "https://files.pythonhosted.org/packages/e2/25/d37215e4562cda5c13312636393aea0bafe38d54d4e0517520a4cc0753ec/rignore-0.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee4a18b82cbbc648e4aac1510066682fe62beb5dc88e2c67c53a83954e541360", size = 1127550, upload-time = "2025-11-05T21:41:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/dc/76/a264ab38bfa1620ec12a8ff1c07778da89e16d8c0f3450b0333020d3d6dc/rignore-0.7.6-cp313-cp313-win32.whl", hash = "sha256:a7d7148b6e5e95035d4390396895adc384d37ff4e06781a36fe573bba7c283e5", size = 646097, upload-time = "2025-11-05T21:41:53.201Z" }, - { url = "https://files.pythonhosted.org/packages/62/44/3c31b8983c29ea8832b6082ddb1d07b90379c2d993bd20fce4487b71b4f4/rignore-0.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:b037c4b15a64dced08fc12310ee844ec2284c4c5c1ca77bc37d0a04f7bff386e", size = 726170, upload-time = "2025-11-05T21:41:38.131Z" }, - { url = "https://files.pythonhosted.org/packages/aa/41/e26a075cab83debe41a42661262f606166157df84e0e02e2d904d134c0d8/rignore-0.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:e47443de9b12fe569889bdbe020abe0e0b667516ee2ab435443f6d0869bd2804", size = 656184, upload-time = "2025-11-05T21:41:27.396Z" }, ] [[package]] @@ -6275,35 +5611,14 @@ 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/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" }, ] [[package]] @@ -6312,23 +5627,10 @@ version = "0.9.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6f/c3/418441a8170e8d53d05c0b9dad69760dbc7b8a12c10dbe6db1e1205d2377/ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933", size = 3717448, upload-time = "2025-02-28T10:16:42.209Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/c3/2c4afa9ba467555d074b146d9aed0633a56ccdb900839fb008295d037b89/ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367", size = 10027252, upload-time = "2025-02-28T10:15:44.182Z" }, - { url = "https://files.pythonhosted.org/packages/33/d1/439e58487cf9eac26378332e25e7d5ade4b800ce1eec7dc2cfc9b0d7ca96/ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7", size = 10840721, upload-time = "2025-02-28T10:15:49.396Z" }, - { url = "https://files.pythonhosted.org/packages/50/44/fead822c38281ba0122f1b76b460488a175a9bd48b130650a6fb6dbcbcf9/ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d", size = 10161439, upload-time = "2025-02-28T10:15:52.522Z" }, { url = "https://files.pythonhosted.org/packages/11/ae/d404a2ab8e61ddf6342e09cc6b7f7846cce6b243e45c2007dbe0ca928a5d/ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a", size = 10336264, upload-time = "2025-02-28T10:15:56.9Z" }, - { url = "https://files.pythonhosted.org/packages/6a/4e/7c268aa7d84cd709fb6f046b8972313142cffb40dfff1d2515c5e6288d54/ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe", size = 9908774, upload-time = "2025-02-28T10:15:59.612Z" }, - { url = "https://files.pythonhosted.org/packages/cc/26/c618a878367ef1b76270fd027ca93692657d3f6122b84ba48911ef5f2edc/ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c", size = 11428127, upload-time = "2025-02-28T10:16:02.94Z" }, - { url = "https://files.pythonhosted.org/packages/d7/9a/c5588a93d9bfed29f565baf193fe802fa676a0c837938137ea6cf0576d8c/ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be", size = 12133187, upload-time = "2025-02-28T10:16:05.632Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ff/e7980a7704a60905ed7e156a8d73f604c846d9bd87deda9cabfa6cba073a/ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590", size = 11602937, upload-time = "2025-02-28T10:16:10.489Z" }, - { url = "https://files.pythonhosted.org/packages/24/78/3690444ad9e3cab5c11abe56554c35f005b51d1d118b429765249095269f/ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb", size = 13771698, upload-time = "2025-02-28T10:16:13.358Z" }, { url = "https://files.pythonhosted.org/packages/6e/bf/e477c2faf86abe3988e0b5fd22a7f3520e820b2ee335131aca2e16120038/ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0", size = 11249026, upload-time = "2025-02-28T10:16:16.154Z" }, { url = "https://files.pythonhosted.org/packages/f7/82/cdaffd59e5a8cb5b14c408c73d7a555a577cf6645faaf83e52fe99521715/ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17", size = 10220432, upload-time = "2025-02-28T10:16:18.798Z" }, - { url = "https://files.pythonhosted.org/packages/fe/a4/2507d0026225efa5d4412b6e294dfe54725a78652a5c7e29e6bd0fc492f3/ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1", size = 9874602, upload-time = "2025-02-28T10:16:21.903Z" }, - { url = "https://files.pythonhosted.org/packages/d5/be/f3aab1813846b476c4bcffe052d232244979c3cd99d751c17afb530ca8e4/ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57", size = 10851212, upload-time = "2025-02-28T10:16:24.793Z" }, { url = "https://files.pythonhosted.org/packages/8b/45/8e5fd559bea0d2f57c4e12bf197a2fade2fac465aa518284f157dfbca92b/ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e", size = 11327490, upload-time = "2025-02-28T10:16:27.654Z" }, - { url = "https://files.pythonhosted.org/packages/42/55/e6c90f13880aeef327746052907e7e930681f26a164fe130ddac28b08269/ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1", size = 10227912, upload-time = "2025-02-28T10:16:31.55Z" }, - { url = "https://files.pythonhosted.org/packages/35/b2/da925693cb82a1208aa34966c0f36cb222baca94e729dd22a587bc22d0f3/ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1", size = 11355632, upload-time = "2025-02-28T10:16:36.144Z" }, - { url = "https://files.pythonhosted.org/packages/31/d8/de873d1c1b020d668d8ec9855d390764cb90cf8f6486c0983da52be8b7b7/ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf", size = 10435860, upload-time = "2025-02-28T10:16:39.481Z" }, ] [[package]] @@ -6349,22 +5651,10 @@ version = "0.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, - { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, - { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, - { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, - { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, - { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, - { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, - { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, - { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, - { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, ] [[package]] @@ -6379,18 +5669,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/aa/e22e0768512ce9255eba34775be2e85c2048da73da1193e841707f8f039c/scikit_learn-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d6ae97234d5d7079dc0040990a6f7aeb97cb7fa7e8945f1999a429b23569e0a", size = 8513770, upload-time = "2025-12-10T07:08:03.251Z" }, - { url = "https://files.pythonhosted.org/packages/58/37/31b83b2594105f61a381fc74ca19e8780ee923be2d496fcd8d2e1147bd99/scikit_learn-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:edec98c5e7c128328124a029bceb09eda2d526997780fef8d65e9a69eead963e", size = 8044458, upload-time = "2025-12-10T07:08:05.336Z" }, { url = "https://files.pythonhosted.org/packages/2d/5a/3f1caed8765f33eabb723596666da4ebbf43d11e96550fb18bdec42b467b/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74b66d8689d52ed04c271e1329f0c61635bcaf5b926db9b12d58914cdc01fe57", size = 8610341, upload-time = "2025-12-10T07:08:07.732Z" }, { url = "https://files.pythonhosted.org/packages/38/cf/06896db3f71c75902a8e9943b444a56e727418f6b4b4a90c98c934f51ed4/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8fdf95767f989b0cfedb85f7ed8ca215d4be728031f56ff5a519ee1e3276dc2e", size = 8900022, upload-time = "2025-12-10T07:08:09.862Z" }, - { url = "https://files.pythonhosted.org/packages/1c/f9/9b7563caf3ec8873e17a31401858efab6b39a882daf6c1bfa88879c0aa11/scikit_learn-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:2de443b9373b3b615aec1bb57f9baa6bb3a9bd093f1269ba95c17d870422b271", size = 7989409, upload-time = "2025-12-10T07:08:12.028Z" }, - { url = "https://files.pythonhosted.org/packages/49/bd/1f4001503650e72c4f6009ac0c4413cb17d2d601cef6f71c0453da2732fc/scikit_learn-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:eddde82a035681427cbedded4e6eff5e57fa59216c2e3e90b10b19ab1d0a65c3", size = 7619760, upload-time = "2025-12-10T07:08:13.688Z" }, - { url = "https://files.pythonhosted.org/packages/d2/7d/a630359fc9dcc95496588c8d8e3245cc8fd81980251079bc09c70d41d951/scikit_learn-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7cc267b6108f0a1499a734167282c00c4ebf61328566b55ef262d48e9849c735", size = 8826045, upload-time = "2025-12-10T07:08:15.215Z" }, - { url = "https://files.pythonhosted.org/packages/cc/56/a0c86f6930cfcd1c7054a2bc417e26960bb88d32444fe7f71d5c2cfae891/scikit_learn-1.8.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:fe1c011a640a9f0791146011dfd3c7d9669785f9fed2b2a5f9e207536cf5c2fd", size = 8420324, upload-time = "2025-12-10T07:08:17.561Z" }, { url = "https://files.pythonhosted.org/packages/46/1e/05962ea1cebc1cf3876667ecb14c283ef755bf409993c5946ade3b77e303/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72358cce49465d140cc4e7792015bb1f0296a9742d5622c67e31399b75468b9e", size = 8680651, upload-time = "2025-12-10T07:08:19.952Z" }, { url = "https://files.pythonhosted.org/packages/fe/56/a85473cd75f200c9759e3a5f0bcab2d116c92a8a02ee08ccd73b870f8bb4/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80832434a6cc114f5219211eec13dcbc16c2bac0e31ef64c6d346cde3cf054cb", size = 8925045, upload-time = "2025-12-10T07:08:22.11Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b7/64d8cfa896c64435ae57f4917a548d7ac7a44762ff9802f75a79b77cb633/scikit_learn-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ee787491dbfe082d9c3013f01f5991658b0f38aa8177e4cd4bf434c58f551702", size = 8507994, upload-time = "2025-12-10T07:08:23.943Z" }, - { url = "https://files.pythonhosted.org/packages/5e/37/e192ea709551799379958b4c4771ec507347027bb7c942662c7fbeba31cb/scikit_learn-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf97c10a3f5a7543f9b88cbf488d33d175e9146115a451ae34568597ba33dcde", size = 7869518, upload-time = "2025-12-10T07:08:25.71Z" }, ] [[package]] @@ -6402,26 +5684,14 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, - { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, - { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, - { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, - { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, - { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, - { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, - { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, - { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, ] [[package]] @@ -6439,22 +5709,10 @@ version = "0.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/15/15/2e7a025fc62d764b151ae6d0f2a92f8081755ebe8d4a64099accc6f77ba6/sentencepiece-0.2.1.tar.gz", hash = "sha256:8138cec27c2f2282f4a34d9a016e3374cd40e5c6e9cb335063db66a0a3b71fad", size = 3228515, upload-time = "2025-08-12T07:00:51.718Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/4a/85fbe1706d4d04a7e826b53f327c4b80f849cf1c7b7c5e31a20a97d8f28b/sentencepiece-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dcd8161eee7b41aae57ded06272905dbd680a0a04b91edd0f64790c796b2f706", size = 1943150, upload-time = "2025-08-12T06:59:53.588Z" }, - { url = "https://files.pythonhosted.org/packages/c2/83/4cfb393e287509fc2155480b9d184706ef8d9fa8cbf5505d02a5792bf220/sentencepiece-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c6c8f42949f419ff8c7e9960dbadcfbc982d7b5efc2f6748210d3dd53a7de062", size = 1325651, upload-time = "2025-08-12T06:59:55.073Z" }, - { url = "https://files.pythonhosted.org/packages/8d/de/5a007fb53b1ab0aafc69d11a5a3dd72a289d5a3e78dcf2c3a3d9b14ffe93/sentencepiece-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:097f3394e99456e9e4efba1737c3749d7e23563dd1588ce71a3d007f25475fff", size = 1253641, upload-time = "2025-08-12T06:59:56.562Z" }, { url = "https://files.pythonhosted.org/packages/2c/d2/f552be5928105588f4f4d66ee37dd4c61460d8097e62d0e2e0eec41bc61d/sentencepiece-0.2.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7b670879c370d350557edabadbad1f6561a9e6968126e6debca4029e5547820", size = 1316271, upload-time = "2025-08-12T06:59:58.109Z" }, { url = "https://files.pythonhosted.org/packages/96/df/0cfe748ace5485be740fed9476dee7877f109da32ed0d280312c94ec259f/sentencepiece-0.2.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7f0fd2f2693309e6628aeeb2e2faf6edd221134dfccac3308ca0de01f8dab47", size = 1387882, upload-time = "2025-08-12T07:00:00.701Z" }, - { url = "https://files.pythonhosted.org/packages/ac/dd/f7774d42a881ced8e1739f393ab1e82ece39fc9abd4779e28050c2e975b5/sentencepiece-0.2.1-cp313-cp313-win32.whl", hash = "sha256:92b3816aa2339355fda2c8c4e021a5de92180b00aaccaf5e2808972e77a4b22f", size = 999541, upload-time = "2025-08-12T07:00:02.709Z" }, - { url = "https://files.pythonhosted.org/packages/dd/e9/932b9eae6fd7019548321eee1ab8d5e3b3d1294df9d9a0c9ac517c7b636d/sentencepiece-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:10ed3dab2044c47f7a2e7b4969b0c430420cdd45735d78c8f853191fa0e3148b", size = 1054669, upload-time = "2025-08-12T07:00:04.915Z" }, - { url = "https://files.pythonhosted.org/packages/c9/3a/76488a00ea7d6931689cda28726a1447d66bf1a4837943489314593d5596/sentencepiece-0.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac650534e2251083c5f75dde4ff28896ce7c8904133dc8fef42780f4d5588fcd", size = 1033922, upload-time = "2025-08-12T07:00:06.496Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b6/08fe2ce819e02ccb0296f4843e3f195764ce9829cbda61b7513f29b95718/sentencepiece-0.2.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:8dd4b477a7b069648d19363aad0cab9bad2f4e83b2d179be668efa672500dc94", size = 1946052, upload-time = "2025-08-12T07:00:08.136Z" }, - { url = "https://files.pythonhosted.org/packages/ab/d9/1ea0e740591ff4c6fc2b6eb1d7510d02f3fb885093f19b2f3abd1363b402/sentencepiece-0.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0c0f672da370cc490e4c59d89e12289778310a0e71d176c541e4834759e1ae07", size = 1327408, upload-time = "2025-08-12T07:00:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/99/7e/1fb26e8a21613f6200e1ab88824d5d203714162cf2883248b517deb500b7/sentencepiece-0.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad8493bea8432dae8d6830365352350f3b4144415a1d09c4c8cb8d30cf3b6c3c", size = 1254857, upload-time = "2025-08-12T07:00:11.021Z" }, { url = "https://files.pythonhosted.org/packages/bc/85/c72fd1f3c7a6010544d6ae07f8ddb38b5e2a7e33bd4318f87266c0bbafbf/sentencepiece-0.2.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b81a24733726e3678d2db63619acc5a8dccd074f7aa7a54ecd5ca33ca6d2d596", size = 1315722, upload-time = "2025-08-12T07:00:12.989Z" }, { url = "https://files.pythonhosted.org/packages/4a/e8/661e5bd82a8aa641fd6c1020bd0e890ef73230a2b7215ddf9c8cd8e941c2/sentencepiece-0.2.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0a81799d0a68d618e89063fb423c3001a034c893069135ffe51fee439ae474d6", size = 1387452, upload-time = "2025-08-12T07:00:15.088Z" }, - { url = "https://files.pythonhosted.org/packages/99/5e/ae66c361023a470afcbc1fbb8da722c72ea678a2fcd9a18f1a12598c7501/sentencepiece-0.2.1-cp313-cp313t-win32.whl", hash = "sha256:89a3ea015517c42c0341d0d962f3e6aaf2cf10d71b1932d475c44ba48d00aa2b", size = 1002501, upload-time = "2025-08-12T07:00:16.966Z" }, - { url = "https://files.pythonhosted.org/packages/c1/03/d332828c4ff764e16c1b56c2c8f9a33488bbe796b53fb6b9c4205ddbf167/sentencepiece-0.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:33f068c9382dc2e7c228eedfd8163b52baa86bb92f50d0488bf2b7da7032e484", size = 1057555, upload-time = "2025-08-12T07:00:18.573Z" }, - { url = "https://files.pythonhosted.org/packages/88/14/5aee0bf0864df9bd82bd59e7711362908e4935e3f9cdc1f57246b5d5c9b9/sentencepiece-0.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:b3616ad246f360e52c85781e47682d31abfb6554c779e42b65333d4b5f44ecc0", size = 1036042, upload-time = "2025-08-12T07:00:20.209Z" }, ] [[package]] @@ -6476,26 +5734,14 @@ version = "1.3.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" }, - { url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" }, { url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" }, { url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" }, - { url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" }, { url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" }, - { url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" }, { url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" }, - { url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" }, - { url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" }, - { url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" }, - { url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" }, { url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" }, { url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" }, - { url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" }, { url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" }, - { url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" }, { url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" }, - { url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" }, - { url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" }, ] [[package]] @@ -6619,13 +5865,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e2/14/19020d822877810d1b047073bb41c54a76802e618296af12344f6caa6d2e/sglang_router-0.3.2.tar.gz", hash = "sha256:bdbea1d54cce879fb83d2885d01ee3c006f242d0adbbac806f2fb2b91a5fe73d", size = 1301869, upload-time = "2026-01-15T19:55:17.856Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/33/1f206e3238a709f0f032f5c2a4c9115a5af12245781a5c8eea9a4e692b6f/sglang_router-0.3.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:111cf062d018ec307b1427c7211c62696447feda13614a84c24f60a5d7907319", size = 27594300, upload-time = "2026-01-15T19:55:00.149Z" }, - { url = "https://files.pythonhosted.org/packages/e6/57/5f6ab7f6940ff1612c94fe250170a026ecdf6bf63fa25f1ebd917579112c/sglang_router-0.3.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:027e498713affb0f7f3ddf72ce7b14f499080137784c258b26321ec8c18d533b", size = 26307573, upload-time = "2026-01-15T19:55:02.879Z" }, { url = "https://files.pythonhosted.org/packages/e7/4f/3e87054427e06f7dd1cc089514d4e29f7946c7c9916009d5fbd3997be6a3/sglang_router-0.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40a10f3817b80377c2ceb326b625f24bd06eb97426e5044de722295ec7fa79c0", size = 31039654, upload-time = "2026-01-15T19:55:05.393Z" }, { url = "https://files.pythonhosted.org/packages/21/37/2ec21a57e77f7bb66c713a819ea6ffa94b6859c6b3ddd062d3b91d856b86/sglang_router-0.3.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba5a24951e5e0357fe390782fcd1abd861448a87216832dbf2e501a1dd1548eb", size = 30726976, upload-time = "2026-01-15T19:55:07.886Z" }, { url = "https://files.pythonhosted.org/packages/91/de/7774e5909ef986e1fe3f2618e4c47d3d97cdf1efaa7909f60a73fc7afac7/sglang_router-0.3.2-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:415be7ed1415a0c931155d2bc8abd74e467a074066b41d956ca944eedbcc9b4b", size = 37141388, upload-time = "2026-01-15T19:55:10.393Z" }, { url = "https://files.pythonhosted.org/packages/47/fb/485c074c67db41d7582760443dcf98e2cf42793b82e699935f48ff04f3b6/sglang_router-0.3.2-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:366183fc84865028b6e63d62adc8ce603667abf0162c393170c8c63be1582a49", size = 38289376, upload-time = "2026-01-15T19:55:12.897Z" }, - { url = "https://files.pythonhosted.org/packages/f8/5f/813b620900310edf41a431f42a7b32f75c793239cb60c454f52f03a52c44/sglang_router-0.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:037f028d6f0e5bae8a84259b49d9857a5427c84653c2d02023fed623ae221530", size = 25838819, upload-time = "2026-01-15T19:55:15.927Z" }, ] [[package]] @@ -6655,17 +5898,10 @@ version = "4.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0e/2a/54837395a3487c725669428d513293612a48d82b95a0642c936932e5d898/simplejson-4.1.1.tar.gz", hash = "sha256:c08eb9f7a90f77ae470e19a07472e9a79ebc0d1c2315d86a72767665bd5ba79f", size = 118860, upload-time = "2026-04-24T19:24:59.819Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/a9/47b445eeb559c9593453a0648e0fd6d08e8adff64dd5e5ced66726da8a09/simplejson-4.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dff52fc7af272e84fc21cc5a06c927c823ca6ae00af14f3b0d7707b42775ed98", size = 113160, upload-time = "2026-04-24T19:23:26.033Z" }, - { url = "https://files.pythonhosted.org/packages/4c/65/cb72db31523c164dea5dc55b02dad065a40c478856bc7534b279d2b51906/simplejson-4.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:971aed0647ad6e840a3943bec812fcda5f2d26a5497a4981d1fb49aa4f9a396c", size = 91521, upload-time = "2026-04-24T19:23:27.572Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e5/54cb7c50ad5fdc1e0a86b7df4b135c2cbd5c4623605aa94466659098e8da/simplejson-4.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:249e2e220aa6d9b9d936bde84eb7bf79d5b6c5a8273c6e411f8b1635a9073f2d", size = 91407, upload-time = "2026-04-24T19:23:28.991Z" }, { url = "https://files.pythonhosted.org/packages/38/2e/21a3ede87f0bf82d6c7bcb90480d50a6490eb974c6ab20881188e440957c/simplejson-4.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e5cdd6a5d52299f345c15ab5678cc4249e24f383f361d986afbc3c7072a6b6b", size = 192451, upload-time = "2026-04-24T19:23:30.56Z" }, { url = "https://files.pythonhosted.org/packages/59/df/9903edd3102bf0b5984edfcb90c88612330996efa3b4fbf8a971d6e17839/simplejson-4.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:642cec364e0676e2d5a73fa4d31d0c7c55886997caa2fde24e8292ca44d32728", size = 189015, upload-time = "2026-04-24T19:23:32.647Z" }, - { url = "https://files.pythonhosted.org/packages/98/cd/33230927a780e1398b857e3944abb914556994d252b1d765ae40d112cb25/simplejson-4.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:76fe296ca1df23d290033f10aaacf534fd1b3e3007e7f9ff8aa68b21413aaa78", size = 196658, upload-time = "2026-04-24T19:23:34.563Z" }, { url = "https://files.pythonhosted.org/packages/cd/84/2c5a7444eb53e9a86d3738299bffddd9f53aeed799ded2f45368221fdb19/simplejson-4.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f0ad25b7dc4e0fb23858355819f2e994f1a5badcdcde8737eac7921c2f1ed2a", size = 185967, upload-time = "2026-04-24T19:23:36.191Z" }, - { url = "https://files.pythonhosted.org/packages/d3/68/454378e06d059cd412a7ed5d87fb6d29fd5b60f13a4d89fc1f764ff434df/simplejson-4.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a59ebd0533f03fd06ff0c42ba0f02d93cbcdd7944922bf3b93911327a95b901f", size = 193940, upload-time = "2026-04-24T19:23:38.151Z" }, { url = "https://files.pythonhosted.org/packages/d5/d5/a15bf915f623a2c5a079d6e3be8256fdb8ef06f110669493a09b9d6933e0/simplejson-4.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bccbf4419676b517939852e5aeff2af6aee4dc046881c67a1581fa6f1cb01abd", size = 189795, upload-time = "2026-04-24T19:23:40.139Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c9/37212ae7dc4b607f0978c408e8633f05c810884e054c33113184c6c2c8a2/simplejson-4.1.1-cp313-cp313-win32.whl", hash = "sha256:6c845363eb5fd166fb7c72243da38f4fcfde666ede7fdf2cc6fd7762894626f7", size = 88773, upload-time = "2026-04-24T19:23:41.754Z" }, - { url = "https://files.pythonhosted.org/packages/fe/a5/c7a0a47883a9015b54c9d8a4b62f2aba17bd4335b1787b9b8a0fc2fa6d52/simplejson-4.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:104d8324c34f25b4b90800bc5fa363780cbc3d8496aef061cba7ce1af9162270", size = 90888, upload-time = "2026-04-24T19:23:43.11Z" }, { url = "https://files.pythonhosted.org/packages/ce/6a/8b74c52ffd33dbbde00fe7251fee6a0acdc8cea33f7a43805aed258fb79b/simplejson-4.1.1-py3-none-any.whl", hash = "sha256:2ce92b3748f02423e26d2bfb636fb9d7a8f67c8f5854dcae69d350d123b2eee2", size = 69195, upload-time = "2026-04-24T19:24:57.962Z" }, ] @@ -6772,12 +6008,8 @@ dependencies = [ sdist = { url = "https://files.pythonhosted.org/packages/e1/41/9b873a8c055582859b239be17902a85339bec6a30ad162f98c9b0288a2cc/soundfile-0.13.1.tar.gz", hash = "sha256:b2c68dab1e30297317080a5b43df57e302584c49e2942defdde0acccc53f0e5b", size = 46156, upload-time = "2025-01-25T09:17:04.831Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/64/28/e2a36573ccbcf3d57c00626a21fe51989380636e821b341d36ccca0c1c3a/soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445", size = 25751, upload-time = "2025-01-25T09:16:44.235Z" }, - { url = "https://files.pythonhosted.org/packages/ea/ab/73e97a5b3cc46bba7ff8650a1504348fa1863a6f9d57d7001c6b67c5f20e/soundfile-0.13.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:82dc664d19831933fe59adad199bf3945ad06d84bc111a5b4c0d3089a5b9ec33", size = 1142250, upload-time = "2025-01-25T09:16:47.583Z" }, - { url = "https://files.pythonhosted.org/packages/a0/e5/58fd1a8d7b26fc113af244f966ee3aecf03cb9293cb935daaddc1e455e18/soundfile-0.13.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:743f12c12c4054921e15736c6be09ac26b3b3d603aef6fd69f9dde68748f2593", size = 1101406, upload-time = "2025-01-25T09:16:49.662Z" }, { url = "https://files.pythonhosted.org/packages/58/ae/c0e4a53d77cf6e9a04179535766b3321b0b9ced5f70522e4caf9329f0046/soundfile-0.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9c9e855f5a4d06ce4213f31918653ab7de0c5a8d8107cd2427e44b42df547deb", size = 1235729, upload-time = "2025-01-25T09:16:53.018Z" }, { url = "https://files.pythonhosted.org/packages/57/5e/70bdd9579b35003a489fc850b5047beeda26328053ebadc1fb60f320f7db/soundfile-0.13.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:03267c4e493315294834a0870f31dbb3b28a95561b80b134f0bd3cf2d5f0e618", size = 1313646, upload-time = "2025-01-25T09:16:54.872Z" }, - { url = "https://files.pythonhosted.org/packages/fe/df/8c11dc4dfceda14e3003bb81a0d0edcaaf0796dd7b4f826ea3e532146bba/soundfile-0.13.1-py2.py3-none-win32.whl", hash = "sha256:c734564fab7c5ddf8e9be5bf70bab68042cd17e9c214c06e365e20d64f9a69d5", size = 899881, upload-time = "2025-01-25T09:16:56.663Z" }, - { url = "https://files.pythonhosted.org/packages/14/e9/6b761de83277f2f02ded7e7ea6f07828ec78e4b229b80e4ca55dd205b9dc/soundfile-0.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:1e70a05a0626524a69e9f0f4dd2ec174b4e9567f4d8b6c11d38b5c289be36ee9", size = 1019162, upload-time = "2025-01-25T09:16:59.573Z" }, ] [[package]] @@ -6798,11 +6030,8 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/ed/11/27cebce4a108f77afea7c80545115536b45e3f11ebfb914f638fdd9ba847/soxr-1.1.0.tar.gz", hash = "sha256:9f228ae21c78fa9359ca98d8a5e8e91f30639e438e574133dace62c5b5309e44", size = 173067, upload-time = "2026-05-03T00:15:18.214Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/8a/f3da7973b5f1b05d2d7e94d5376b881dcbc05297900cae6c3d33d95b209b/soxr-1.1.0-cp312-abi3-macosx_10_14_x86_64.whl", hash = "sha256:e0e09fa633ce2e67df08b298afced4d184f6e753fc330f241022250f1d0d61da", size = 204124, upload-time = "2026-05-03T00:14:54.505Z" }, - { url = "https://files.pythonhosted.org/packages/03/dc/200013a74641f8774664bbcd2346c695c05c2e300ea792adcb40a293eed0/soxr-1.1.0-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6a7ad82b8d5f3fcc04b1d2ca055562b96af571e1d4fa7c6c61d0fb509ac43b4", size = 165457, upload-time = "2026-05-03T00:14:56.007Z" }, { url = "https://files.pythonhosted.org/packages/88/2b/2e5eba817a762a2ec589ff165b8bc5955b25a0ad140045f7cd8e45410543/soxr-1.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf98c0d7b7d5ef5bf072fee8d3020e8b664f2d195933ea7bc5089267c2e22a06", size = 206529, upload-time = "2026-05-03T00:14:57.646Z" }, { url = "https://files.pythonhosted.org/packages/5c/f1/0e55195893228609c9a08c3b13b7a83a46c3a992cd00d3304f0f320cfb07/soxr-1.1.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b033078e86f3c4a658e5697fac8995764fad9e799563616b630136b613167f1", size = 240413, upload-time = "2026-05-03T00:14:59.363Z" }, - { url = "https://files.pythonhosted.org/packages/b0/4d/621e4150e4815246ad552d215a8a294a90143fedd19ee442cf82d3b3abc8/soxr-1.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:6ae2a174bffea94e8ead857dad85999d3f49f091774dbad5b046c0417d7092f4", size = 174357, upload-time = "2026-05-03T00:15:00.724Z" }, ] [[package]] @@ -6886,18 +6115,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/cf/45dd359f6ca0c3762ce0490f681da242f0530c49c81050c035c016bfdd3a/sphinx_design-0.7.0-py3-none-any.whl", hash = "sha256:f82bf179951d58f55dca78ab3706aeafa496b741a91b1911d371441127d64282", size = 2220350, upload-time = "2026-01-19T13:12:51.077Z" }, ] -[[package]] -name = "sphinx-reredirects" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/8d/0e39fe2740d7d71417edf9a6424aa80ca2c27c17fc21282cdc39f90d5a40/sphinx_reredirects-1.1.0.tar.gz", hash = "sha256:fb9b195335ab14b43f8273287d0c7eeb637ba6c56c66581c11b47202f6718b29", size = 614624, upload-time = "2025-12-22T08:28:02.792Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/81/b5dd07067f3daac6d23687ec737b2d593740671ebcd145830c8f92d381c5/sphinx_reredirects-1.1.0-py3-none-any.whl", hash = "sha256:4b5692273c72cd2d4d917f4c6f87d5919e4d6114a752d4be033f7f5f6310efd9", size = 6351, upload-time = "2025-12-22T08:27:59.724Z" }, -] - [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" @@ -6976,19 +6193,14 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/81/81755f50eb2478eaf2049728491d4ea4f416c1eb013338682173259efa09/sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120", size = 2154547, upload-time = "2026-04-03T16:53:08.64Z" }, { url = "https://files.pythonhosted.org/packages/a2/bc/3494270da80811d08bcfa247404292428c4fe16294932bce5593f215cad9/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2", size = 3280782, upload-time = "2026-04-03T17:07:43.508Z" }, { url = "https://files.pythonhosted.org/packages/cd/f5/038741f5e747a5f6ea3e72487211579d8cbea5eb9827a9cbd61d0108c4bd/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3", size = 3297156, upload-time = "2026-04-03T17:12:27.697Z" }, { url = "https://files.pythonhosted.org/packages/88/50/a6af0ff9dc954b43a65ca9b5367334e45d99684c90a3d3413fc19a02d43c/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7", size = 3228832, upload-time = "2026-04-03T17:07:45.38Z" }, { url = "https://files.pythonhosted.org/packages/bc/d1/5f6bdad8de0bf546fc74370939621396515e0cdb9067402d6ba1b8afbe9a/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33", size = 3267000, upload-time = "2026-04-03T17:12:29.657Z" }, - { url = "https://files.pythonhosted.org/packages/f7/30/ad62227b4a9819a5e1c6abff77c0f614fa7c9326e5a3bdbee90f7139382b/sqlalchemy-2.0.49-cp313-cp313-win32.whl", hash = "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b", size = 2115641, upload-time = "2026-04-03T17:05:43.989Z" }, - { url = "https://files.pythonhosted.org/packages/17/3a/7215b1b7d6d49dc9a87211be44562077f5f04f9bb5a59552c1c8e2d98173/sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl", hash = "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148", size = 2141498, upload-time = "2026-04-03T17:05:45.7Z" }, { url = "https://files.pythonhosted.org/packages/28/4b/52a0cb2687a9cd1648252bb257be5a1ba2c2ded20ba695c65756a55a15a4/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518", size = 3560807, upload-time = "2026-04-03T16:58:31.666Z" }, { url = "https://files.pythonhosted.org/packages/8c/d8/fda95459204877eed0458550d6c7c64c98cc50c2d8d618026737de9ed41a/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d", size = 3527481, upload-time = "2026-04-03T17:06:00.155Z" }, { url = "https://files.pythonhosted.org/packages/ff/0a/2aac8b78ac6487240cf7afef8f203ca783e8796002dc0cf65c4ee99ff8bb/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0", size = 3468565, upload-time = "2026-04-03T16:58:33.414Z" }, { url = "https://files.pythonhosted.org/packages/a5/3d/ce71cfa82c50a373fd2148b3c870be05027155ce791dc9a5dcf439790b8b/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08", size = 3477769, upload-time = "2026-04-03T17:06:02.787Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e8/0a9f5c1f7c6f9ca480319bf57c2d7423f08d31445974167a27d14483c948/sqlalchemy-2.0.49-cp313-cp313t-win32.whl", hash = "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d", size = 2143319, upload-time = "2026-04-03T17:02:04.328Z" }, - { url = "https://files.pythonhosted.org/packages/0e/51/fb5240729fbec73006e137c4f7a7918ffd583ab08921e6ff81a999d6517a/sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl", hash = "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba", size = 2175104, upload-time = "2026-04-03T17:02:05.989Z" }, { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, ] @@ -7169,7 +6381,6 @@ version = "0.7.2" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb", size = 2356, upload-time = "2023-10-23T21:23:32.16Z" }, - { url = "https://files.pythonhosted.org/packages/b7/85/dabeaf902892922777492e1d253bb7e1264cadce3cea932f7ff599e53fea/tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60", size = 4823598, upload-time = "2023-10-23T21:23:33.714Z" }, { url = "https://files.pythonhosted.org/packages/73/c6/825dab04195756cf8ff2e12698f22513b3db2f64925bdd41671bfb33aaa5/tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530", size = 6590363, upload-time = "2023-10-23T21:23:35.583Z" }, ] @@ -7186,14 +6397,10 @@ dependencies = [ { name = "torch", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-fsdp') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-mcore') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-automodel' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-fsdp' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-sglang') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-mcore' and extra == 'extra-7-nemo-rl-vllm') or (sys_platform != 'linux' and extra == 'extra-7-nemo-rl-sglang' and extra == 'extra-7-nemo-rl-vllm')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/99/e8/ec3f0d5c1c96ff2ffe6eee27030aacf4c863a2d936a7e17fcd1b6cb63c3d/tensordict-0.12.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:853b6420c2458861434855453d75052b55887bcca2c4958fe9883813ba30a913", size = 890147, upload-time = "2026-05-22T00:09:29.602Z" }, { url = "https://files.pythonhosted.org/packages/4f/c3/ae214fbda9f2fe85bca76b272a7924d6a8b58990ba1b167028ae79bc0a85/tensordict-0.12.4-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3cfd1124b1931780b9e193a9fe7b37d50e5229dae4eaa715db5608c28803a710", size = 533774, upload-time = "2026-05-22T00:09:31.619Z" }, { url = "https://files.pythonhosted.org/packages/ed/3f/7e7f87da0a343ae234fc346653e812710c0c7823ceb1034b35652f7cbd90/tensordict-0.12.4-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:43e190dc05d217af3d27c207125db90ff5de1a7c5945aab34430a0d5cf81f7fd", size = 537544, upload-time = "2026-05-22T00:09:33.524Z" }, - { url = "https://files.pythonhosted.org/packages/77/0a/b765ae434ef1650b3f538fdc5ec979b2188a2c3e839a6dddb3b173f6d033/tensordict-0.12.4-cp313-cp313-win_amd64.whl", hash = "sha256:0d96da5907b7a5dbd10782a4166eb0e82a702e805b11f94a28bd629da61dff36", size = 586791, upload-time = "2026-05-22T00:09:35.659Z" }, - { url = "https://files.pythonhosted.org/packages/b3/84/c84936bdc4c2d1432f96d4e16f2521e196208332f985de6329bb8398d127/tensordict-0.12.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:a1e23296684e532650e236228c59fe0f4dd323d7c409c0798c18fd2791c1e252", size = 895573, upload-time = "2026-05-22T00:09:37.429Z" }, { url = "https://files.pythonhosted.org/packages/6d/b6/d574e2b758631563861d51cba4cc595d27a3965db3473a05ab268eead05b/tensordict-0.12.4-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:6e60888bc24990ead02d52f16fa607af8c01c92089ad767540eca88ade5fb49f", size = 535213, upload-time = "2026-05-22T00:09:39.561Z" }, { url = "https://files.pythonhosted.org/packages/13/a4/25c29e653878e58ed3cb111146e4dd8cdb4cfd4b6f66dd2080f94f8e78f4/tensordict-0.12.4-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:031c70d2101376e0fb8036b017c8271a27892c1b9ba6aea021c039c7535aac53", size = 539088, upload-time = "2026-05-22T00:09:41.377Z" }, - { url = "https://files.pythonhosted.org/packages/35/6f/c8107ea679a60e7584bc6d36b854879a33f5a990819e174a7ed653edb781/tensordict-0.12.4-cp313-cp313t-win_amd64.whl", hash = "sha256:a1320ea2ed9e0289209b0efc51b8bf2bca02cf5273fade3aec4f60a4ddfed61b", size = 597644, upload-time = "2026-05-22T00:09:42.922Z" }, ] [[package]] @@ -7215,20 +6422,14 @@ dependencies = [ ] 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/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]] @@ -7254,7 +6455,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e6/27/6e363f48f878389078e2899756b8fecc326388b585122fd7f8a86590dfab/tilelang-0.1.8.tar.gz", hash = "sha256:da967821698eb7a79a76d27fbe25e314a3273f2b12ba4833e981658139d0e6d9", size = 93247335, upload-time = "2026-02-16T14:03:28.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/17/10ab5c8ccc58783edcc5392ba653f4732702e44a72065224b3d7a4971852/tilelang-0.1.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:83654bff38448b6b26e143f150c928360619e91bf431289cf6cd74a4b31c7eba", size = 36016575, upload-time = "2026-02-16T14:02:54.054Z" }, { url = "https://files.pythonhosted.org/packages/5d/0b/96ba853aa9e4795020d183e0ca832e9e37d82d4f7f48896241323d1b5ece/tilelang-0.1.8-cp38-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a4018e581f55c852d98a42d3b4acf2dbcfb8b7d8b9156ba7c6b0ab61600a10c", size = 43477401, upload-time = "2026-02-16T14:03:02.879Z" }, { url = "https://files.pythonhosted.org/packages/e6/db/d130c8db9140bb21a2ef81a455614a4aeec3388088bf9af5df01ad0ba45d/tilelang-0.1.8-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:bcc2e28202cde516bdd59e1c25b7f6a139d1c52207d92576f4e711c6217e16ba", size = 40422585, upload-time = "2026-02-16T14:03:12.092Z" }, ] @@ -7283,7 +6483,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/56/70/5051f65821baa30a3d61fc48f8ba10c776490315e8c90f82559b92089756/tilelang-0.1.9.tar.gz", hash = "sha256:287f727c913bb648fcf6c1968809ba3390e55eeed257a5c6bb9a80bc05966af4", size = 93395292, upload-time = "2026-04-22T09:19:11.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/db/4dd76da8c8585c605639a21bc098d504e317fe324a72f01ce3c7370250b4/tilelang-0.1.9-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:00ed594fdeb229c5505b9ffa895c3c5daeb28641c78f783fa1f724cf1e08cecd", size = 36599020, upload-time = "2026-04-22T09:14:39.366Z" }, { url = "https://files.pythonhosted.org/packages/f7/8a/1cbeee79d62abaa02441c2d00621554e41aa62dbf3b94a4feb3867184b01/tilelang-0.1.9-cp38-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bbccfe9035aed775ffafb6dc25a5994504b24e2c5d95d0f39643edfafa7bf12", size = 45419374, upload-time = "2026-04-22T09:15:56.014Z" }, { url = "https://files.pythonhosted.org/packages/c6/a7/f4bfb86f87e107703146e703204cec2c0eae2492b633e0052b0ace3febb6/tilelang-0.1.9-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:77ab0ee2f40f66ea015b6b21426d482751e28cbc635ef9d1198cbd6502454a7c", size = 42110365, upload-time = "2026-04-22T09:17:18.292Z" }, ] @@ -7313,21 +6512,10 @@ dependencies = [ ] 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]] @@ -7386,10 +6574,8 @@ dependencies = [ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c3d60f79666b9101e3914a2e5dec2e81eac834e13cae0bcf59e94dc1a465f756", upload-time = "2026-04-27T20:04:49Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:554461b76f21211927c776056bcb0b00fb42972364794b686d768ebb0b586366", upload-time = "2026-04-27T20:05:21Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:339801f2163698a53c7fb3c91883e7f44331d22c34d45acfbce4eff71f2332fa", upload-time = "2026-04-27T20:06:44Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:a33905bc3e093b25d2b019181cf834f7f7d4c562739e13dd36a798ecb2e411b0", upload-time = "2026-04-27T20:08:23Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6fd10ed484eb695312ae829719888bb9f6c7f5e8503528e3e8ad1b98a45296c2", upload-time = "2026-04-27T20:08:56Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:21d2734fd02af45d19bb88c0ff2e86b238ce73f7bde6003ade7f1454ae299198", upload-time = "2026-04-27T20:10:20Z" }, ] [[package]] @@ -7401,10 +6587,8 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/37/de/921b6491efce5c389a5ef9bbed3d2d6660005840dae488124173180859ab/torch_c_dlpack_ext-0.1.5.tar.gz", hash = "sha256:d06f0357d575d22a168cc77acb9020fc4bae30968ceb6718a055dcbe92bacabe", size = 12913, upload-time = "2026-01-12T11:25:08.484Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/c6/65346a201d921b616731311fc9941f15137672b444cebdad702cb52ccee0/torch_c_dlpack_ext-0.1.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:74acea2ed395cadda63342845b9e9ee7cd4537846223dacfb4431b4610109265", size = 1993243, upload-time = "2026-01-12T11:24:51.079Z" }, { url = "https://files.pythonhosted.org/packages/fd/ec/faf10be09a5812b1c5ec9922b53fb5def5fc4080b81a653b9347bb169ebb/torch_c_dlpack_ext-0.1.5-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49f1e99d13c64e22dac0a34a1560e9e5a398a49a9fa81df83053e04fde6ec5bd", size = 443798, upload-time = "2026-01-12T11:24:52.754Z" }, { url = "https://files.pythonhosted.org/packages/2d/68/f434b48700f3e04f33882f54d8d3910327b935f55e14ec49da7d607bf470/torch_c_dlpack_ext-0.1.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:debe62e5ef93e631065d6b9f6e60d3d39bae6b89fa1b25d9523f40b3efbf8aba", size = 755004, upload-time = "2026-01-12T11:24:54.004Z" }, - { url = "https://files.pythonhosted.org/packages/03/a8/cc64e563f05ea99bd79bdb43f71f0f46452d3acd734da4843ede5fc73a35/torch_c_dlpack_ext-0.1.5-cp313-cp313-win_amd64.whl", hash = "sha256:30e3eab616dbc81dfdb7492aca557be551a9163ba9b585f97394a42b336b113a", size = 999126, upload-time = "2026-01-12T11:24:55.44Z" }, ] [[package]] @@ -7433,10 +6617,8 @@ source = { registry = "https://download.pytorch.org/whl/cu130" } wheels = [ { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:23498b01097648e304e78d6495a9f5bdce8441a802afc3025e2561973d74c025", upload-time = "2026-03-23T15:50:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e9c07cfdab691454092ff12d21dd1407a4bb8ad081d38f222cf6fcf6abcc18c8", upload-time = "2026-03-23T15:50:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:ce09a7b144b7982b46c8fe399cf5f91d43dda571e9d6ddba67e928567551f614", upload-time = "2026-03-23T15:50:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:f9b277a0d3b2ab4385778146b7e879716f36b6f2080f7190ec744e3383511791", upload-time = "2026-03-23T15:50:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:d07c4cbe4bec3e15bb18ba163058038f5f5fc1775c3061685c194439af4d2e9f", upload-time = "2026-03-23T15:50:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchaudio-2.11.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:b9dd151f06842ca77dc341aed94ea2f5d13a89e5027aa032a47198d073bcf3db", upload-time = "2026-03-23T15:50:26Z" }, ] [[package]] @@ -7444,10 +6626,8 @@ name = "torchcodec" version = "0.11.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/61/a8985a7561ef651e409deeac151a0ed5cef763db9577db5cc49c2f5eaab2/torchcodec-0.11.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:915fbe20068ec77486fbbeaf0c627c89c7376445f27d215b7489c0a03c64fd4c", size = 4289805, upload-time = "2026-04-14T18:24:59.124Z" }, { url = "https://files.pythonhosted.org/packages/7a/31/c4ec0304dd169a9b2b7fa0dd1d5d659d3cccc975b98ac88c498fe6dd7196/torchcodec-0.11.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3755de03c96afd37410cba68198225d11cd6431a32f2161a0019791a4a853305", size = 2399057, upload-time = "2026-04-14T18:25:00.782Z" }, { url = "https://files.pythonhosted.org/packages/5d/b2/85ad7a81f387e40983c21bc94da0c333974afb41f38c3a85d25875274187/torchcodec-0.11.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5eee69971cec1147a03b8a6b678b5dfbeff0b2c71ed7929e488391f9fbcd630c", size = 2332721, upload-time = "2026-04-14T18:25:02.518Z" }, - { url = "https://files.pythonhosted.org/packages/ad/ca/5c66f21d2a12039450e9dd4d9d7c480019dfbe9e8a87696a3c3a827c1e37/torchcodec-0.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:67b34e5733636588ebe0f15082bbb90a8ce1472ccb8bb1a656ec28958a208919", size = 1920990, upload-time = "2026-04-14T18:25:04.269Z" }, ] [[package]] @@ -7475,10 +6655,8 @@ dependencies = [ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3af2c699719cc0e2518bf317664200e5a987fb75a25b9b3bf3817a4796ddd64f", upload-time = "2026-03-23T15:36:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:441a98bed4fff1d54b8450499e377e1a605bec31f2ecb1a38a340f95dcc83897", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:64de855465d6de60583e776889fad9412480f9f9e04fdd8d17ae96fa93864e9a", upload-time = "2026-04-09T23:21:54Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c3ac485da79552b4f579c525c826f7a63288b0d1cafc1201b16e1148bfdea69a", upload-time = "2026-03-23T15:36:26Z" }, { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:110659ff38cd1d2ca0ac6e6a0f2c842fcb5fe739dfe65ff7456a12b2c4dce775", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:a7e19c3ab5c6d8e3c9f8c6d427f6b8862dfb8227ea4a758ea7a709951daf2f0d", upload-time = "2026-04-09T23:21:55Z" }, ] [[package]] @@ -7721,8 +6899,6 @@ 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/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" }, @@ -8112,15 +7288,10 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/8e/31/fe53d06b75ef0a7f2f0ee5931a89f7aedc27d233840b1839616860fed256/wandb-0.27.0.tar.gz", hash = "sha256:579e75300173059f9334e1f513a79ef15f6d9ea5c74e20d695633648cdd02031", size = 41090732, upload-time = "2026-05-14T03:44:08.894Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/5e/2c199e70e636ecfd217cde0bc7469f4511e1d03d0685eb92bfdfce391430/wandb-0.27.0-py3-none-macosx_12_0_arm64.whl", hash = "sha256:c156be4851485f3c4160cb6eb2e8991b4cdeffbccefc5636d33cf5e254847365", size = 24886476, upload-time = "2026-05-14T03:43:27.569Z" }, - { url = "https://files.pythonhosted.org/packages/0b/cd/a617c871cd304a9804e56a7ec2ec2c65685bf0091a2b9f91910175a149e2/wandb-0.27.0-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:20179f38afb0158859a4141d29ac650d3fdbd0cf801a74ce25565c934f03776c", size = 26045779, upload-time = "2026-05-14T03:43:31.999Z" }, { url = "https://files.pythonhosted.org/packages/10/0a/d3f159a201530b84b72ca5f98c68d1f351c2d9a1864558ed76c811407fae/wandb-0.27.0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:626497d7975fa898d0a4a239da7a510483495ca3514510dbe75004a25963af4d", size = 25480764, upload-time = "2026-05-14T03:43:35.922Z" }, { url = "https://files.pythonhosted.org/packages/5f/6a/8721fcdf71d42639191040a77a585d2982402b1754700cb2ecfc2ca1470a/wandb-0.27.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:f772da7005cc26a2a32b729a16982a583dc68b3d493df6a09d0aa5c5ca5a2060", size = 27256204, upload-time = "2026-05-14T03:43:39.765Z" }, { url = "https://files.pythonhosted.org/packages/00/5e/279d167ba79fb7a8a43401c9f25efd0f6663ee9bd1eaf5a8578530198888/wandb-0.27.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:63acfc5b994e4a90e4a2fbdee6d45e664da3dd865bb1419942c8995c06c41cf1", size = 25647469, upload-time = "2026-05-14T03:43:44.817Z" }, { url = "https://files.pythonhosted.org/packages/94/51/a69ac59300e3c813939d0764348959ed2a21e14c668cb1cebcb04010da6a/wandb-0.27.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:17aae6e4a88cd05c00ea8f546220918e3ebb6f8c1c36b70ef04a5ac75f0d7160", size = 27599005, upload-time = "2026-05-14T03:43:50.926Z" }, - { url = "https://files.pythonhosted.org/packages/5f/40/bf510c8758727df020f83b717ebc1fcc1739ed7f6ae1796ebef60bf6f592/wandb-0.27.0-py3-none-win32.whl", hash = "sha256:0bd5659417e386bf6538b5e2ffe6885774c6197f0e4853bfed517d5b0db457f1", size = 25036164, upload-time = "2026-05-14T03:43:54.839Z" }, - { url = "https://files.pythonhosted.org/packages/54/ff/69f88e7d90c22b79bcb911143c13e59742ee192080b21015ff83a5a1f60a/wandb-0.27.0-py3-none-win_amd64.whl", hash = "sha256:89d584b73166eecee96fb446f18d0e45b1aa45aba6a3696296f3f06d7454516b", size = 25036170, upload-time = "2026-05-14T03:43:59.227Z" }, - { url = "https://files.pythonhosted.org/packages/f6/38/f7efd7a87297a55c7e9a331a1dbb5b19e54aeacc11fe6f43f8636a73987c/wandb-0.27.0-py3-none-win_arm64.whl", hash = "sha256:a6c129c311edf210a2b4f2f4acc557eff522628125f5f28ed27df19c16c07079", size = 22972710, upload-time = "2026-05-14T03:44:03.275Z" }, ] [[package]] @@ -8132,26 +7303,11 @@ dependencies = [ ] 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/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" }, @@ -8181,15 +7337,10 @@ 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/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/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] @@ -8223,28 +7374,14 @@ version = "2.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload-time = "2026-03-06T02:53:41.922Z" }, - { url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload-time = "2026-03-06T02:52:48.672Z" }, { url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload-time = "2026-03-06T02:54:14.013Z" }, { url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload-time = "2026-03-06T02:54:10.829Z" }, - { url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload-time = "2026-03-06T02:53:03.623Z" }, { url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload-time = "2026-03-06T02:53:45.844Z" }, - { url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload-time = "2026-03-06T02:54:46.356Z" }, { url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload-time = "2026-03-06T02:52:50.163Z" }, - { url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload-time = "2026-03-06T02:53:47.494Z" }, - { url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload-time = "2026-03-06T02:53:30.038Z" }, - { url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload-time = "2026-03-06T02:52:52.114Z" }, - { url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload-time = "2026-03-06T02:53:19.108Z" }, - { url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload-time = "2026-03-06T02:54:33.452Z" }, { url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload-time = "2026-03-06T02:52:42.721Z" }, { url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload-time = "2026-03-06T02:54:25.441Z" }, - { url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload-time = "2026-03-06T02:53:57.456Z" }, { url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload-time = "2026-03-06T02:54:55.309Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload-time = "2026-03-06T02:54:24.092Z" }, { url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload-time = "2026-03-06T02:53:31.268Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload-time = "2026-03-06T02:54:15.391Z" }, - { url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload-time = "2026-03-06T02:54:41.943Z" }, - { url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload-time = "2026-03-06T02:54:48.093Z" }, { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] @@ -8284,10 +7421,8 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/db/43/e5dfddb1d2a4fccf3e3a88f103e88698cdefc3182f4e169a359ffe1c1794/xgrammar-0.1.33.tar.gz", hash = "sha256:8dbe5fc3d76651ab1fac7a68fc2a118b885fa0ec7189927fb6e0dce0081aea99", size = 2398956, upload-time = "2026-03-27T10:16:36.582Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/b1/cce9f6d12b9de0db8b86401ea739fe79ac555f3da56e47faa5b874d41e42/xgrammar-0.1.33-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e5b46b922fb04fd1848198da5273ddc20f16693fba5871bac1837f1c90f59584", size = 22702353, upload-time = "2026-03-27T10:15:27.203Z" }, { url = "https://files.pythonhosted.org/packages/6b/55/4d186d4065f645a051be992919c51aaf96cfa8a32f7ecc8512a6e41f969f/xgrammar-0.1.33-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7eec984a20fd54d4c79536d99e2515bac54bd4e1380162fa047f5ff45bdf6d8", size = 42133430, upload-time = "2026-03-27T10:15:31.409Z" }, { url = "https://files.pythonhosted.org/packages/2b/ca/db765035b3bb1854bdb833c118e0f09dacc623ce5e867466d63610d635fa/xgrammar-0.1.33-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d705f62d91a3675997a81d09aa371c375d7793ce1021aff7b7ed5a92021c7379", size = 42206830, upload-time = "2026-03-27T10:15:35.574Z" }, - { url = "https://files.pythonhosted.org/packages/f5/17/635fc8933b35f24d0749fe177209abb5b526c99a2d098abb71c0e601f356/xgrammar-0.1.33-cp313-cp313-win_amd64.whl", hash = "sha256:2c626de8f503858efa28cab099cbb1719c4926af4250e8dea8efddfa2c6b6c91", size = 7222102, upload-time = "2026-03-27T10:15:38.617Z" }, ] [[package]] @@ -8296,49 +7431,17 @@ version = "3.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/24/2f/e183a1b407002f5af81822bee18b61cdb94b8670208ef34734d8d2b8ebe9/xxhash-3.7.0.tar.gz", hash = "sha256:6cc4eefbb542a5d6ffd6d70ea9c502957c925e800f998c5630ecc809d6702bae", size = 82022, upload-time = "2026-04-25T11:10:32.553Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ca/d5174b4c36d10f64d4ca7050563138c5a599efb01a765858ddefc9c1202a/xxhash-3.7.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:4b6d6b33f141158692bd4eafbb96edbc5aa0dabdb593a962db01a91983d4f8fa", size = 36813, upload-time = "2026-04-25T11:06:51.73Z" }, - { url = "https://files.pythonhosted.org/packages/41/d0/abc6c9d347ba1f1e1e1d98125d0881a0452c7f9a76a9dd03a7b5d2197f23/xxhash-3.7.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:845d347df254d6c619f616afa921331bada8614b8d373d58725c663ba97c3605", size = 35121, upload-time = "2026-04-25T11:06:53.048Z" }, { url = "https://files.pythonhosted.org/packages/bf/11/4cc834eb3d79f2f2b3a6ef7324195208bcdfbdcf7534d2b17267aa5f3a8f/xxhash-3.7.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:fddbbb69a6fff4f421e7a0d1fa28f894b20112e9e3fab306af451e2dfd0e459b", size = 29624, upload-time = "2026-04-25T11:06:54.311Z" }, { url = "https://files.pythonhosted.org/packages/23/83/e97d3e7b635fe73a1dfb1e91f805324dd6d930bb42041cbf18f183bc0b6d/xxhash-3.7.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:54876a4e45101cec2bf8f31a973cda073a23e2e108538dad224ba07f85f22487", size = 30638, upload-time = "2026-04-25T11:06:55.864Z" }, { url = "https://files.pythonhosted.org/packages/f4/40/d84951d80c35db1f4c40a29a64a8520eea5d56e764c603906b4fe763580f/xxhash-3.7.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:0c72fe9c7e3d6dfd7f1e21e224a877917fa09c465694ba4e06464b9511b65544", size = 33323, upload-time = "2026-04-25T11:06:57.336Z" }, - { url = "https://files.pythonhosted.org/packages/89/cc/c7dc6558d97e9ab023f663d69ab28b340ed9bf4d2d94f2c259cf896bb354/xxhash-3.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a6d73a830b17ef49bc04e00182bd839164c1b3c59c127cd7c54fcb10c7ed8ee8", size = 33362, upload-time = "2026-04-25T11:06:58.656Z" }, - { url = "https://files.pythonhosted.org/packages/2a/6e/46b84017b1301d54091430353d4ad5901654a3e0871649877a416f7f1644/xxhash-3.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c3b07cf3362086d8f126c6aecd8e5e9396ad8b2f2219ea7e49a8250c318acd", size = 30874, upload-time = "2026-04-25T11:06:59.834Z" }, - { url = "https://files.pythonhosted.org/packages/df/5e/8f9158e3ab906ad3fec51e09b5ea0093e769f12207bfa42a368ca204e7ab/xxhash-3.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:50e879ebbac351c81565ca108db766d7832f5b8b6a5b14b8c0151f7190028e3d", size = 194185, upload-time = "2026-04-25T11:07:01.658Z" }, { url = "https://files.pythonhosted.org/packages/f3/29/a804ded9f5d3d3758292678d23e7528b08fda7b7e750688d08b052322475/xxhash-3.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:921c14e93817842dd0dd9f372890a0f0c72e534650b6ab13c5be5cd0db11d47e", size = 213033, upload-time = "2026-04-25T11:07:03.606Z" }, - { url = "https://files.pythonhosted.org/packages/8b/91/1ce5a7d2fdc975267320e2c78fc1cecfe7ab735ccbcf6993ec5dd541cb2c/xxhash-3.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e64a7c9d7dfca3e0fafcbc5e455519090706a3e36e95d655cec3e04e79f95aaa", size = 236140, upload-time = "2026-04-25T11:07:05.396Z" }, - { url = "https://files.pythonhosted.org/packages/34/04/fd595a4fd8617b05fa27bd9b684ecb4985bfed27917848eea85d54036d06/xxhash-3.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2220af08163baf5fa36c2b8af079dc2cbe6e66ae061385267f9472362dfd53c6", size = 212291, upload-time = "2026-04-25T11:07:06.966Z" }, - { url = "https://files.pythonhosted.org/packages/03/fb/f1a379cbc372ae5b9f4ab36154c48a849ca6ebe3ac477067a57865bf3bc6/xxhash-3.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f14bb8b22a4a91325813e3d553b8963c10cf8c756cff65ee50c194431296c655", size = 445532, upload-time = "2026-04-25T11:07:08.525Z" }, { url = "https://files.pythonhosted.org/packages/65/59/172424b79f8cfd4b6d8a122b2193e6b8ad4b11f7159bb3b6f9b3191329bb/xxhash-3.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:496736f86a9bedaf64b0dc70e3539d0766df01c71ea22032698e88f3f04a1ce9", size = 193990, upload-time = "2026-04-25T11:07:10.315Z" }, - { url = "https://files.pythonhosted.org/packages/b9/19/aeac22161d953f139f07ba5586cb4a17c5b7b6dff985122803bb12933500/xxhash-3.7.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0ff71596bd79816975b3de7130ab1ff4541410285a3c084584eeb1c8239996fd", size = 284876, upload-time = "2026-04-25T11:07:12.15Z" }, { url = "https://files.pythonhosted.org/packages/77/d5/4fd0b59e7a02242953da05ff679fbb961b0a4368eac97a217e11dae110c1/xxhash-3.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1ad86695c19b1d46fe106925db3c7a37f16be37669dcf58dcc70a9dd6e324676", size = 210495, upload-time = "2026-04-25T11:07:13.952Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fb/976a3165c728c7faf74aa1b5ab3cf6a85e6d731612894741840524c7d28c/xxhash-3.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:970f9f8c50961d639cbd0d988c96f80ddf66006de93641719282c4fe7a87c5e6", size = 241331, upload-time = "2026-04-25T11:07:15.557Z" }, - { url = "https://files.pythonhosted.org/packages/4a/2c/6763d5901d53ac9e6ba296e5717ae599025c9d268396e8faa8b4b0a8e0ac/xxhash-3.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5886ad85e9e347911783760a1d16cb6b393e8f9e3b52c982568226cb56927bdc", size = 198037, upload-time = "2026-04-25T11:07:17.563Z" }, - { url = "https://files.pythonhosted.org/packages/61/2b/876e722d533833f5f9a83473e6ba993e48745701096944e77bbecf29b2c3/xxhash-3.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6e934bbae1e0ec74e27d5f0d7f37ef547ce5ff9f0a7e63fb39e559fc99526734", size = 210744, upload-time = "2026-04-25T11:07:19.055Z" }, - { url = "https://files.pythonhosted.org/packages/21/e6/d7e7baef7ce24166b4668d3c48557bb35a23b92ecadcac7e7718d099ab69/xxhash-3.7.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:3b6b3d28228af044ebcded71c4a3dd86e1dbd7e2f4645bf40f7b5da65bb5fb5a", size = 275406, upload-time = "2026-04-25T11:07:20.908Z" }, - { url = "https://files.pythonhosted.org/packages/92/fe/198b3763b2e01ca908f2154969a2352ec99bda892b574a11a9a151c5ede4/xxhash-3.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:6be4d70d9ab76c9f324ead9c01af6ff52c324745ea0c3731682a0cf99720f1fe", size = 414125, upload-time = "2026-04-25T11:07:23.037Z" }, { url = "https://files.pythonhosted.org/packages/3a/6d/019a11affd5a5499137cacca53808659964785439855b5aa40dfd3412916/xxhash-3.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:151d7520838d4465461a0b7f4ae488b3b00de16183dd3214c1a6b14bf89d7fb6", size = 191555, upload-time = "2026-04-25T11:07:24.991Z" }, - { url = "https://files.pythonhosted.org/packages/76/21/b96d58568df2d01533244c3e0e5cbdd0c8b2b25c4bec4d72f19259a292d7/xxhash-3.7.0-cp313-cp313-win32.whl", hash = "sha256:d798c1e291bffb8e37b5bbe0dda77fc767cd19e89cadaf66e6ed5d0ff88c9fe6", size = 30668, upload-time = "2026-04-25T11:07:26.665Z" }, - { url = "https://files.pythonhosted.org/packages/99/57/d849a8d3afa1f8f4bc6a831cd89f49f9706fbbad94d2975d6140a171988c/xxhash-3.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:875811ba23c543b1a1c3143c926e43996eb27ebb8f52d3500744aa608c275aed", size = 31524, upload-time = "2026-04-25T11:07:27.92Z" }, - { url = "https://files.pythonhosted.org/packages/81/52/bacc753e92dee78b058af8dcef0a50815f5f860986c664a92d75f965b6a5/xxhash-3.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:54a675cb300dda83d71daae2a599389d22db8021a0f8db0dd659e14626eb3ecc", size = 27768, upload-time = "2026-04-25T11:07:29.113Z" }, - { url = "https://files.pythonhosted.org/packages/1c/47/ddbd683b7fc7e592c1a8d9d65f73ce9ab513f082b3967eee2baf549b8fc6/xxhash-3.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a3b19a42111c4057c1547a4a1396a53961dca576a0f6b82bfa88a2d1561764b2", size = 33576, upload-time = "2026-04-25T11:07:30.469Z" }, - { url = "https://files.pythonhosted.org/packages/07/f2/36d3310161db7f72efb4562aadde0ed429f1d0531782dd6345b12d2da527/xxhash-3.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8f4608a06e4d61b7a3425665a46d00e0579122e1a2fae97a0c52953a3aad9aa3", size = 31123, upload-time = "2026-04-25T11:07:31.989Z" }, - { url = "https://files.pythonhosted.org/packages/0d/3f/75937a5c69556ed213021e43cbedd84c8e0279d0d74e7d41a255d84ba4b1/xxhash-3.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ad37c7792479e49cf96c1ab25517d7003fe0d93687a772ba19a097d235bbe41e", size = 196491, upload-time = "2026-04-25T11:07:33.358Z" }, { url = "https://files.pythonhosted.org/packages/22/29/f10d7ff8c7a733d4403a43b9de18c8fabc005f98cec054644f04418659ee/xxhash-3.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc026e3b89d98e30a8288c95cb696e77d150b3f0fb7a51f73dcd49ee6b5577fa", size = 215793, upload-time = "2026-04-25T11:07:34.919Z" }, - { url = "https://files.pythonhosted.org/packages/8b/fd/778f60aa295f58907938f030a8b514611f391405614a525cccd2ffc00eb5/xxhash-3.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c9b31ab1f28b078a6a1ac1a54eb35e7d5390deddd56870d0be3a0a733d1c321c", size = 237993, upload-time = "2026-04-25T11:07:36.638Z" }, - { url = "https://files.pythonhosted.org/packages/70/f5/736db5de387b4a540e37a05b84b40dc58a1ce974bfd2b4e5754ce29b68c3/xxhash-3.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3bb5fd680c038fd5229e44e9c493782f90df9bef632fd0499d442374688ff70b", size = 214887, upload-time = "2026-04-25T11:07:38.564Z" }, - { url = "https://files.pythonhosted.org/packages/4d/aa/09a095f22fdb9a27fbb716841fbff52119721f9ca4261952d07a912f7839/xxhash-3.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:030c0fd688fce3569fbb49a2feefd4110cbb0b650186fb4610759ecfac677548", size = 448407, upload-time = "2026-04-25T11:07:40.552Z" }, { url = "https://files.pythonhosted.org/packages/74/8a/b745efeeca9e34a91c26fdc97ad8514c43d5a81ac78565cba80a1353870a/xxhash-3.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b1bde10324f4c31812ae0d0502e92d916ae8917cad7209353f122b8b8f610c3", size = 196119, upload-time = "2026-04-25T11:07:42.101Z" }, - { url = "https://files.pythonhosted.org/packages/8a/5c/0cfceb024af90c191f665c7933b1f318ee234f4797858383bebd1881d52f/xxhash-3.7.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:503722d52a615f2604f5e7611de7d43878df010dc0053094ef91cb9a9ac3d987", size = 286751, upload-time = "2026-04-25T11:07:43.568Z" }, { url = "https://files.pythonhosted.org/packages/0b/0a/0793e405dc3cf8f4ebe2c1acec1e4e4608cd9e7e50ea691dabbc2a95ccbb/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c72500a3b6d6c30ebfc135035bcace9eb5884f2dc220804efcaaba43e9f611dd", size = 212961, upload-time = "2026-04-25T11:07:45.388Z" }, - { url = "https://files.pythonhosted.org/packages/0c/7e/721118ffc63bfff94aa565bcf2555a820f9f4bdb0f001e0d609bdfad70de/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:43475925a766d01ca8cd9a857fd87f3d50406983c8506a4c07c4df12adcc867f", size = 243703, upload-time = "2026-04-25T11:07:47.053Z" }, - { url = "https://files.pythonhosted.org/packages/6e/18/16f6267160488b8276fd3d449d425712512add292ba545c1b6946bfdb7dd/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8d09dfd2ab135b985daf868b594315ebe11ad86cd9fea46e6c69f19b28f7d25a", size = 200894, upload-time = "2026-04-25T11:07:48.657Z" }, - { url = "https://files.pythonhosted.org/packages/2d/94/80ba841287fd97e3e9cac1d228788c8ef623746f570404961eec748ecb5c/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c50269d0055ac1faecfd559886d2cbe4b730de236585aba0e873f9d9dadbe585", size = 213357, upload-time = "2026-04-25T11:07:50.257Z" }, - { url = "https://files.pythonhosted.org/packages/a1/7e/106d4067130c59f1e18a55ffadcd876d8c68534883a1e02685b29d3d8153/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:1910df4756a5ab58cfad8744fc2d0f23926e3efcc346ee76e87b974abab922f4", size = 277600, upload-time = "2026-04-25T11:07:51.745Z" }, - { url = "https://files.pythonhosted.org/packages/c5/86/a081dd30da71d720b2612a792bfd55e45fa9a07ac76a0507f60487473c25/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d006faf3b491957efcb433489be3c149efe4787b7063d5cddb8ddaefdc60e0c1", size = 416980, upload-time = "2026-04-25T11:07:53.504Z" }, { url = "https://files.pythonhosted.org/packages/35/29/1a95221a029a3c1293773869e1ab47b07cbbdd82444a42809e8c60156626/xxhash-3.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:abb65b4e947e958f7b3b0d71db3ce447d1bc5f37f5eab871ce7223bda8768a04", size = 193840, upload-time = "2026-04-25T11:07:55.103Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e0/db909dd0823285de2286f67e10ee4d81e96ad35d7d8e964ecb07fccd8af9/xxhash-3.7.0-cp313-cp313t-win32.whl", hash = "sha256:178959906cb1716a1ce08e0d69c82886c70a15a6f2790fc084fdd146ca30cd49", size = 30966, upload-time = "2026-04-25T11:07:56.524Z" }, - { url = "https://files.pythonhosted.org/packages/7b/ff/d705b15b22f21ee106adce239cb65d35067a158c630b240270f09b17c2e6/xxhash-3.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2524a1e20d4c231d13b50f7cf39e44265b055669a64a7a4b9a2a44faa03f19b6", size = 31784, upload-time = "2026-04-25T11:07:57.758Z" }, - { url = "https://files.pythonhosted.org/packages/a2/1f/b2cf83c3638fd0588e0b17f22e5a9400bdfb1a3e3755324ac0aee2250b88/xxhash-3.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:37d994d0ffe81ef087bb330d392caa809bb5853c77e22ea3f71db024a0543dba", size = 27932, upload-time = "2026-04-25T11:07:59.109Z" }, ] [[package]] @@ -8347,15 +7450,10 @@ version = "1.7.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9f/47/f7ec7744dff1104560d6276f951a8182f5b805e8d86ece591aebd0512845/yappi-1.7.6.tar.gz", hash = "sha256:c94281936af77c00c6ac2306a0e7f85a67e354d717120df85fcc5dfb9243d4dd", size = 62639, upload-time = "2026-03-17T22:31:40.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/b0/9a10f3a22290b67e23f339318fd368c173547478e0896f89363fb9cf190b/yappi-1.7.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:072df6fa8b4cfb5159c261dd0df8e8b85de0adbadbc5e953e1183da193674bc4", size = 33299, upload-time = "2026-03-17T22:31:06.04Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ca/f36ccb82d7c96dee3858d26ed08e67de1767c309f285dbb2f76eceeaba48/yappi-1.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e4643d431656ec63e83455605ba29d1609d36b2fe14412e6939a223c323a7aee", size = 33193, upload-time = "2026-03-17T22:31:07.293Z" }, { url = "https://files.pythonhosted.org/packages/17/04/078db90359b39496f9192e375cd97831b138794cf456ad43bd8c7b65a4e3/yappi-1.7.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b27541c7f77ef2f76b2e0bb5da6dce5dc5fcdc7e500b4756e7a3e077d499ac25", size = 83096, upload-time = "2026-03-17T22:31:08.205Z" }, { url = "https://files.pythonhosted.org/packages/f0/52/24e214e5d4093e7b137fac95958afe289d1153ad35e6556be348c55a0b6a/yappi-1.7.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e100b6c36b922fc407078ed74f08b2463f46efc1fb440387eb493966e4ec434", size = 82639, upload-time = "2026-03-17T22:31:09.121Z" }, { url = "https://files.pythonhosted.org/packages/6d/d9/19b43be0e0f2a72518ec4907138614d4f98027839c10cd6b9b3a607cca2a/yappi-1.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5beecd15ff133c93fc505669754cb7caadd7fb19e87a71af133dfd1410e17aff", size = 80278, upload-time = "2026-03-17T22:31:10.039Z" }, { url = "https://files.pythonhosted.org/packages/68/9e/9fa404fee5eb4942ad36409b5d00e3783bd573982aa84f22c8a2646a7125/yappi-1.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3b5742d39c1ebe8909db0dec4a5b724a5a6167161864280021298f7ef4e76a1", size = 80337, upload-time = "2026-03-17T22:31:11.299Z" }, - { url = "https://files.pythonhosted.org/packages/92/2a/a42901c467259e10193c66a24bff410f041896ecdd3cb7b42dd515a54b2a/yappi-1.7.6-cp313-cp313-win32.whl", hash = "sha256:c9e3a92a04d9d6199fa0d157139beff1ca7eea7389e0e6b46b1353d8ffeec6a3", size = 32897, upload-time = "2026-03-17T22:31:12.219Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6c/dede83e0ca33701681acdb06854e492010257ae83bd9dda8e953983fab3a/yappi-1.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:95f9f326483d111b768f630a2d60689de7defff777f016b1f0dab9e93f36beb5", size = 35215, upload-time = "2026-03-17T22:31:13.084Z" }, - { url = "https://files.pythonhosted.org/packages/3a/b0/dec448196d207b2e3b4e6b27dd74d0f1714b645af4f25cfe7dfd564ec14f/yappi-1.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:4981a243c5dbf105f6e1415197935ca36fde2b28adf26d2feceb95b5f1f77f06", size = 32861, upload-time = "2026-03-17T22:31:14.292Z" }, ] [[package]] @@ -8369,42 +7467,14 @@ dependencies = [ ] 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/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" }, ] @@ -8414,12 +7484,8 @@ version = "4.15.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8a/8e/0c8f17309549d2e5cde9a3ccefa6365437f1e7bafe71878eaf9478e47b18/z3_solver-4.15.4.0.tar.gz", hash = "sha256:928c29b58c4eb62106da51c1914f6a4a55d0441f8f48a81b9da07950434a8946", size = 5018600, upload-time = "2025-10-29T18:12:03.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/33/a3d5d2eaeb0f7b3174d57d405437eabb2075d4d50bd9ea0957696c435c7b/z3_solver-4.15.4.0-py3-none-macosx_13_0_arm64.whl", hash = "sha256:407e825cc9211f95ef46bdc8d151bf630e7ab2d62a21d24cd74c09cc5b73f3aa", size = 37052538, upload-time = "2025-10-29T18:11:46.233Z" }, - { url = "https://files.pythonhosted.org/packages/47/84/fd7ffac1551cd9f8d44fe41358f738be670fc4c24dfd514fab503f2cf3e7/z3_solver-4.15.4.0-py3-none-macosx_13_0_x86_64.whl", hash = "sha256:00bd10c5a6a5f6112d3a9a810d0799227e52f76caa860dafa5e00966bb47eb13", size = 39807925, upload-time = "2025-10-29T18:11:49.81Z" }, { url = "https://files.pythonhosted.org/packages/21/c9/bb51a96af0091324c81b803f16c49f719f9f6ea0b0bb52200f5c97ec4892/z3_solver-4.15.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e103a6f203f505b8b8b8e5c931cc407c95b61556512d4921c1ddc0b3f41b08e", size = 29268352, upload-time = "2025-10-29T18:11:53.032Z" }, { url = "https://files.pythonhosted.org/packages/bf/2e/0b49f7e4e53817cfb09a0f6585012b782dfe0b666e8abefcb4fac0570606/z3_solver-4.15.4.0-py3-none-manylinux_2_34_aarch64.whl", hash = "sha256:62c7e9cbdd711932301f29919ad9158de9b2f58b4d281dd259bbcd0a2f408ba1", size = 27226534, upload-time = "2025-10-29T18:11:55.59Z" }, - { url = "https://files.pythonhosted.org/packages/26/91/33de49538444d4aafbe47415c450c2f9abab1733e1226f276b496672f46c/z3_solver-4.15.4.0-py3-none-win32.whl", hash = "sha256:be3bc916545c96ffbf89e00d07104ff14f78336e55db069177a1bfbcc01b269d", size = 13191672, upload-time = "2025-10-29T18:11:58.424Z" }, - { url = "https://files.pythonhosted.org/packages/03/d6/a0b135e4419df475177ae78fc93c422430b0fd8875649486f9a5989772e6/z3_solver-4.15.4.0-py3-none-win_amd64.whl", hash = "sha256:00e35b02632ed085ea8199fb230f6015e6fc40554a6680c097bd5f060e827431", size = 16259597, upload-time = "2025-10-29T18:12:01.14Z" }, ] [[package]]