diff --git a/pyproject.toml b/pyproject.toml index 7051cc1b5..e6a047b6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,9 @@ dependencies = [ "textual-plot>=0.10.1", "tree-sitter>=0.24.0", "tree-sitter-python>=0.23.0,<0.26.0", + "ifbench @ git+https://github.com/allenai/IFBench.git@finbarr/clean-install", + # syllapy (transitive via ifbench) imports pkg_resources, which setuptools>=81 removes. + "setuptools<81", ] [project.urls] @@ -222,6 +225,8 @@ allowed-unresolved-imports = [ "google.cloud.**", "matplotlib.**", "scipy.**", + "instructions_registry.**", + "instructions.**", ] [tool.gantry] diff --git a/src/olmo_eval/common/metrics/__init__.py b/src/olmo_eval/common/metrics/__init__.py index f4b06406a..c20521f9e 100644 --- a/src/olmo_eval/common/metrics/__init__.py +++ b/src/olmo_eval/common/metrics/__init__.py @@ -19,6 +19,12 @@ SQuADF1Metric, ToolAccuracyMetric, ) +from .ifeval import ( + IFEvalInstLooseAccuracy, + IFEvalInstStrictAccuracy, + IFEvalPromptLooseAccuracy, + IFEvalPromptStrictAccuracy, +) __all__ = [ "AccuracyMetric", @@ -27,6 +33,10 @@ "CorpusPerplexityMetric", "F1Metric", "GreedyAccuracyMetric", + "IFEvalInstLooseAccuracy", + "IFEvalInstStrictAccuracy", + "IFEvalPromptLooseAccuracy", + "IFEvalPromptStrictAccuracy", "LogprobMCAccuracyMetric", "LogprobPerCharMCAccuracyMetric", "LogprobPerTokenMCAccuracyMetric", diff --git a/src/olmo_eval/common/metrics/ifeval.py b/src/olmo_eval/common/metrics/ifeval.py new file mode 100644 index 000000000..01b85a040 --- /dev/null +++ b/src/olmo_eval/common/metrics/ifeval.py @@ -0,0 +1,87 @@ +"""IFBench / IFEval metrics. + +All four metrics share :class:`IFEvalScorer`, which writes per-instruction +strict and loose pass lists to ``output.metadata["ifeval"]``. Each metric +aggregates that side-band data along the prompt or instruction axis. +""" + +from __future__ import annotations + +from collections.abc import Sequence +from dataclasses import dataclass +from typing import ClassVar + +from olmo_eval.common.metrics.base import Metric +from olmo_eval.common.scorers import IFEvalScorer, Scorer +from olmo_eval.common.types import Response + + +def _iter_results(responses: Sequence[Response], key: str) -> list[list[bool]]: + out: list[list[bool]] = [] + for response in responses: + if not response.outputs: + out.append([]) + continue + meta = response.outputs[0].metadata or {} + ifeval = meta.get("ifeval") or {} + out.append(list(ifeval.get(key, []))) + return out + + +def _prompt_level(results: list[list[bool]]) -> float: + if not results: + return 0.0 + correct = sum(1 for r in results if r and all(r)) + return correct / len(results) + + +def _instruction_level(results: list[list[bool]]) -> float: + total = sum(len(r) for r in results) + if total == 0: + return 0.0 + correct = sum(1 for r in results for v in r if v) + return correct / total + + +@dataclass(frozen=True, slots=True) +class IFEvalPromptStrictAccuracy(Metric): + """Fraction of prompts where every instruction passes under strict scoring.""" + + name: ClassVar[str] = "prompt_level_strict_acc" + scorer: ClassVar[type[Scorer]] = IFEvalScorer + + def compute(self, responses: Sequence[Response]) -> float: + return _prompt_level(_iter_results(responses, "strict")) + + +@dataclass(frozen=True, slots=True) +class IFEvalPromptLooseAccuracy(Metric): + """Fraction of prompts where every instruction passes under loose scoring.""" + + name: ClassVar[str] = "prompt_level_loose_acc" + scorer: ClassVar[type[Scorer]] = IFEvalScorer + + def compute(self, responses: Sequence[Response]) -> float: + return _prompt_level(_iter_results(responses, "loose")) + + +@dataclass(frozen=True, slots=True) +class IFEvalInstStrictAccuracy(Metric): + """Fraction of individual instructions passing under strict scoring.""" + + name: ClassVar[str] = "inst_level_strict_acc" + scorer: ClassVar[type[Scorer]] = IFEvalScorer + + def compute(self, responses: Sequence[Response]) -> float: + return _instruction_level(_iter_results(responses, "strict")) + + +@dataclass(frozen=True, slots=True) +class IFEvalInstLooseAccuracy(Metric): + """Fraction of individual instructions passing under loose scoring.""" + + name: ClassVar[str] = "inst_level_loose_acc" + scorer: ClassVar[type[Scorer]] = IFEvalScorer + + def compute(self, responses: Sequence[Response]) -> float: + return _instruction_level(_iter_results(responses, "loose")) diff --git a/src/olmo_eval/common/scorers/__init__.py b/src/olmo_eval/common/scorers/__init__.py index 38b078863..83e131316 100644 --- a/src/olmo_eval/common/scorers/__init__.py +++ b/src/olmo_eval/common/scorers/__init__.py @@ -15,6 +15,7 @@ ) from .code_execution import CodeExecutionScorer, MultiplEScorer from .execution import ContextScorer, ExecutionScorer, SandboxRequiredError +from .ifeval import IFEvalScorer from .llm_judge import ( JudgeFn, LLMJudgeScorer, @@ -45,6 +46,7 @@ "ExactMatchScorer", "ExecutionScorer", "F1Scorer", + "IFEvalScorer", "JudgeFn", "LLMJudgeScorer", "LogprobScorer", diff --git a/src/olmo_eval/common/scorers/ifeval.py b/src/olmo_eval/common/scorers/ifeval.py new file mode 100644 index 000000000..d4e231e11 --- /dev/null +++ b/src/olmo_eval/common/scorers/ifeval.py @@ -0,0 +1,104 @@ +"""Scorer for IFBench / IFEval instruction-following evaluation. + +Uses the ``ifbench`` package registry, which covers the original IFEval +(DEFAULT) verifiers, the OOD verifiers used by ``allenai/IFBench_test2``, +and the verifiers used by the multi-turn ``VGraf/ifeval_mt`` slices. The +scorer evaluates a response against per-instance instructions (looked up +in ``instance.metadata["instruction_id_list"]`` / ``"kwargs"``) and writes +both strict and loose pass/fail lists for each instruction into +``output.metadata["ifeval"]``. The four IFEval metrics consume that field. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, ClassVar + +from olmo_eval.common.scorers.base import Scorer +from olmo_eval.common.types import Instance, LMOutput + + +def _loose_response_variants(response: str) -> list[str]: + """Generate the eight response variants used by upstream loose scoring.""" + lines = response.split("\n") + remove_first = "\n".join(lines[1:]).strip() + remove_last = "\n".join(lines[:-1]).strip() + remove_both = "\n".join(lines[1:-1]).strip() + return [ + response, + response.replace("*", ""), + remove_first, + remove_last, + remove_both, + remove_first.replace("*", ""), + remove_last.replace("*", ""), + remove_both.replace("*", ""), + ] + + +def _check_one( + instruction_cls: Any, + instruction_id: str, + kwargs: dict[str, Any], + prompt: str, + response: str, +) -> bool: + instruction = instruction_cls(instruction_id) + cleaned_kwargs = {k: v for k, v in kwargs.items() if v is not None} + arg_keys = instruction.get_instruction_args_keys() + if "prompt_to_repeat" in arg_keys and not cleaned_kwargs.get("prompt_to_repeat"): + cleaned_kwargs["prompt_to_repeat"] = prompt + instruction.build_description(**cleaned_kwargs) + args = instruction.get_instruction_args() + if args and "prompt" in args: + instruction.build_description(prompt=prompt) + return bool(response.strip()) and bool(instruction.check_following(response)) + + +@dataclass(frozen=True) +class IFEvalScorer(Scorer): + """Run IFBench/IFEval instruction verifiers against a response. + + The numeric ``score()`` return is the prompt-level loose accuracy (1.0 if + every instruction passes under at least one loose variant, else 0.0). The + full strict + loose pass lists are written to ``output.metadata["ifeval"]`` + so the four metric classes can derive prompt/inst × strict/loose figures. + """ + + name: ClassVar[str] = "ifeval" + + def score(self, instance: Instance, output: LMOutput) -> float: + instruction_ids: list[str] = instance.metadata.get("instruction_id_list", []) + kwargs_list: list[dict[str, Any]] = instance.metadata.get("kwargs", []) + prompt: str = instance.metadata.get("prompt", instance.question) + response: str = output.text or "" + + strict_results: list[bool] = [] + loose_results: list[bool] = [] + + if instruction_ids: + from ifbench import instructions_registry + + registry = instructions_registry.INSTRUCTION_DICT + loose_variants = _loose_response_variants(response) + for inst_id, inst_kwargs in zip(instruction_ids, kwargs_list, strict=True): + instruction_cls = registry[inst_id] + strict_results.append( + _check_one(instruction_cls, inst_id, inst_kwargs, prompt, response) + ) + loose_pass = any( + _check_one(instruction_cls, inst_id, inst_kwargs, prompt, variant) + for variant in loose_variants + ) + loose_results.append(loose_pass) + + if output.metadata is None: + output.metadata = {} + output.metadata["ifeval"] = { + "strict": strict_results, + "loose": loose_results, + } + + if not loose_results: + return 0.0 + return 1.0 if all(loose_results) else 0.0 diff --git a/src/olmo_eval/evals/suites/ifbench.py b/src/olmo_eval/evals/suites/ifbench.py new file mode 100644 index 000000000..df42f037c --- /dev/null +++ b/src/olmo_eval/evals/suites/ifbench.py @@ -0,0 +1,13 @@ +"""IFBench (Tulu) instruction-following suite.""" + +from olmo_eval.evals.suites.registry import make_suite + +IFBENCH = make_suite( + "ifbench", + ( + "ifeval_mt_wildchat_unused_withRewrite", + "ifeval_mt_ood_wildchat_unused_withRewrite", + "ifeval_ood", + ), + description="IFBench (Tulu): OOD + multi-turn instruction following", +) diff --git a/src/olmo_eval/evals/tasks/ifeval_mt.py b/src/olmo_eval/evals/tasks/ifeval_mt.py new file mode 100644 index 000000000..4a21e5107 --- /dev/null +++ b/src/olmo_eval/evals/tasks/ifeval_mt.py @@ -0,0 +1,104 @@ +"""IFEval-MT: multi-turn instruction following from ``VGraf/ifeval_mt``. + +Each row of the dataset is a multi-turn conversation that ends in a user turn +asking the assistant to rewrite/repeat its prior reply under a list of +instructions. ``instruction_id_list`` and ``kwargs`` are scored against the +final assistant reply using the same IFEval verifiers as ``ifeval_ood``. + +Two registered variants follow ``IFBENCH_MT_TASKS`` in oe-eval-internal: + +- ``ifeval_mt_wildchat_unused_withRewrite`` (HF subset + ``wildchat_unused_withRewrite``) +- ``ifeval_mt_ood_wildchat_unused_withRewrite`` (HF subset + ``ood_wildchat_unused_withRewrite``) +""" + +from __future__ import annotations + +from collections.abc import Iterator +from typing import Any + +from olmo_eval.common.metrics import ( + IFEvalInstLooseAccuracy, + IFEvalInstStrictAccuracy, + IFEvalPromptLooseAccuracy, + IFEvalPromptStrictAccuracy, +) +from olmo_eval.common.types import ( + Instance, + LMOutput, + LMRequest, + RequestType, + SamplingParams, + Split, +) +from olmo_eval.data import DataSource +from olmo_eval.evals.tasks.common import Task, register + +_PRIMARY_METRIC = IFEvalPromptLooseAccuracy() +_DATASET_PATH = "VGraf/ifeval_mt" +_SAMPLING_PARAMS = SamplingParams( + max_tokens=2048, + temperature=0.0, + do_sample=False, +) + + +class _IFEvalMTBase(Task): + split = Split.TEST + metrics = ( + IFEvalPromptStrictAccuracy(), + IFEvalPromptLooseAccuracy(), + IFEvalInstStrictAccuracy(), + IFEvalInstLooseAccuracy(), + ) + primary_metric = _PRIMARY_METRIC + sampling_params = _SAMPLING_PARAMS + + @property + def instances(self) -> Iterator[Instance]: + yield from self._load_instances_cached() + + @property + def request_type(self) -> RequestType: + return RequestType.CHAT + + def process_doc(self, doc: dict[str, Any], index: int = 0) -> Instance | None: + prompt = doc["prompt"] + instruction_id_list = list(doc.get("instruction_id_list") or []) + raw_kwargs = doc.get("kwargs") or [] + kwargs_list = [{k: v for k, v in (kw or {}).items() if v is not None} for kw in raw_kwargs] + messages = tuple({"role": m["role"], "content": m["content"]} for m in doc["messages"]) + return Instance( + question=prompt, + gold_answer=None, + metadata={ + "id": doc.get("id", doc.get("key", index)), + "key": doc.get("key", doc.get("id", index)), + "prompt": prompt, + "instruction_id_list": instruction_id_list, + "kwargs": kwargs_list, + "messages": messages, + }, + ) + + def format_request(self, instance: Instance) -> LMRequest: + return LMRequest( + request_type=RequestType.CHAT, + messages=tuple(instance.metadata["messages"]), + ) + + def extract_answer(self, output: LMOutput) -> str: + return output.text + + +@register("ifeval_mt_wildchat_unused_withRewrite") +class IFEvalMTWildchatUnusedWithRewrite(_IFEvalMTBase): + data_source = DataSource(path=_DATASET_PATH, subset="wildchat_unused_withRewrite", split="test") + + +@register("ifeval_mt_ood_wildchat_unused_withRewrite") +class IFEvalMTOODWildchatUnusedWithRewrite(_IFEvalMTBase): + data_source = DataSource( + path=_DATASET_PATH, subset="ood_wildchat_unused_withRewrite", split="test" + ) diff --git a/src/olmo_eval/evals/tasks/ifeval_ood.py b/src/olmo_eval/evals/tasks/ifeval_ood.py new file mode 100644 index 000000000..d3c65991c --- /dev/null +++ b/src/olmo_eval/evals/tasks/ifeval_ood.py @@ -0,0 +1,85 @@ +"""IFEval OOD: out-of-distribution instruction-following slice of IFBench. + +Dataset: ``allenai/IFBench_test2`` (300 prompts), each carrying a list of +instruction IDs and per-instruction kwargs. Verifiers come from the vendored +registry in :mod:`olmo_eval.common.scorers.ifeval_deps`. + +Mirrors the ``ifeval_ood::tulu`` configuration in oe-eval-internal: chat +format, ``max_gen_toks=2048``, primary metric ``prompt_level_loose_acc``. +""" + +from __future__ import annotations + +from collections.abc import Iterator +from typing import Any + +from olmo_eval.common.metrics import ( + IFEvalInstLooseAccuracy, + IFEvalInstStrictAccuracy, + IFEvalPromptLooseAccuracy, + IFEvalPromptStrictAccuracy, +) +from olmo_eval.common.types import ( + Instance, + LMOutput, + LMRequest, + RequestType, + SamplingParams, + Split, +) +from olmo_eval.data import DataSource +from olmo_eval.evals.tasks.common import Task, register + +_PRIMARY_METRIC = IFEvalPromptLooseAccuracy() + + +@register("ifeval_ood") +class IFEvalOOD(Task): + data_source = DataSource(path="allenai/IFBench_test2", split="train") + split = Split.TRAIN + metrics = ( + IFEvalPromptStrictAccuracy(), + IFEvalPromptLooseAccuracy(), + IFEvalInstStrictAccuracy(), + IFEvalInstLooseAccuracy(), + ) + primary_metric = _PRIMARY_METRIC + sampling_params = SamplingParams( + max_tokens=2048, + temperature=0.0, + do_sample=False, + ) + + @property + def instances(self) -> Iterator[Instance]: + yield from self._load_instances_cached() + + @property + def request_type(self) -> RequestType: + return RequestType.CHAT + + def process_doc(self, doc: dict[str, Any], index: int = 0) -> Instance | None: + prompt = doc["prompt"] + instruction_id_list = list(doc.get("instruction_id_list") or []) + raw_kwargs = doc.get("kwargs") or [] + kwargs_list = [{k: v for k, v in (kw or {}).items() if v is not None} for kw in raw_kwargs] + return Instance( + question=prompt, + gold_answer=None, + metadata={ + "id": doc.get("key", index), + "key": doc.get("key", index), + "prompt": prompt, + "instruction_id_list": instruction_id_list, + "kwargs": kwargs_list, + }, + ) + + def format_request(self, instance: Instance) -> LMRequest: + return LMRequest( + request_type=RequestType.CHAT, + messages=({"role": "user", "content": instance.question},), + ) + + def extract_answer(self, output: LMOutput) -> str: + return output.text diff --git a/tests/evals/tasks/test_ifbench.py b/tests/evals/tasks/test_ifbench.py new file mode 100644 index 000000000..ae61409b4 --- /dev/null +++ b/tests/evals/tasks/test_ifbench.py @@ -0,0 +1,201 @@ +"""Tests for IFBench tasks (ifeval_ood + ifeval_mt) and the IFEval scoring stack.""" + +from __future__ import annotations + +import unittest +from typing import Any + +from olmo_eval.common.metrics import ( + IFEvalInstLooseAccuracy, + IFEvalInstStrictAccuracy, + IFEvalPromptLooseAccuracy, + IFEvalPromptStrictAccuracy, +) +from olmo_eval.common.scorers import IFEvalScorer +from olmo_eval.common.types import Instance, LMOutput, LMRequest, RequestType, Response +from olmo_eval.evals.suites.registry import get_suite +from olmo_eval.evals.tasks.common import get_task + + +def _make_instance( + prompt: str, + instruction_id_list: list[str], + kwargs_list: list[dict[str, Any]], +) -> Instance: + return Instance( + question=prompt, + gold_answer=None, + metadata={ + "id": "test", + "key": "test", + "prompt": prompt, + "instruction_id_list": instruction_id_list, + "kwargs": kwargs_list, + }, + ) + + +def _make_response(instance: Instance, response_text: str) -> Response: + return Response( + instance=instance, + request=LMRequest(request_type=RequestType.COMPLETION, prompt=instance.question), + outputs=[LMOutput(text=response_text)], + ) + + +class TestIFEvalOODTask(unittest.TestCase): + def test_registered(self) -> None: + task = get_task("ifeval_ood") + self.assertIsNotNone(task) + metric_names = {m.name for m in task.config.metrics} + self.assertEqual( + metric_names, + { + "prompt_level_strict_acc", + "prompt_level_loose_acc", + "inst_level_strict_acc", + "inst_level_loose_acc", + }, + ) + self.assertEqual(task.request_type, RequestType.CHAT) + + def test_process_doc_strips_none_kwargs(self) -> None: + task = get_task("ifeval_ood") + doc = { + "key": 0, + "prompt": "hi", + "instruction_id_list": ["count:numbers"], + "kwargs": [{"N": 2, "keyword": None, "frequency": None}], + } + instance = task.process_doc(doc, index=0) + self.assertIsNotNone(instance) + assert instance is not None + self.assertEqual(instance.metadata["instruction_id_list"], ["count:numbers"]) + self.assertEqual(instance.metadata["kwargs"], [{"N": 2}]) + self.assertEqual(instance.metadata["key"], 0) + + +class TestIFEvalMTTask(unittest.TestCase): + def test_registered_variants(self) -> None: + for name in ( + "ifeval_mt_wildchat_unused_withRewrite", + "ifeval_mt_ood_wildchat_unused_withRewrite", + ): + task = get_task(name) + self.assertIsNotNone(task) + self.assertEqual(task.request_type, RequestType.CHAT) + + def test_process_doc_preserves_messages(self) -> None: + task = get_task("ifeval_mt_wildchat_unused_withRewrite") + messages = [ + {"role": "user", "content": "say hi"}, + {"role": "assistant", "content": "hi"}, + {"role": "user", "content": "Rewrite with exactly 2 numbers."}, + ] + doc = { + "id": "x", + "key": 0, + "prompt": "Rewrite with exactly 2 numbers.", + "instruction_id_list": ["count:numbers"], + "kwargs": [{"N": 2}], + "messages": messages, + } + instance = task.process_doc(doc, index=0) + assert instance is not None + self.assertEqual(len(instance.metadata["messages"]), 3) + self.assertEqual(instance.metadata["messages"][-1]["content"], messages[-1]["content"]) + request = task.format_request(instance) + self.assertEqual(request.request_type, RequestType.CHAT) + self.assertEqual(len(request.messages), 3) + + +class TestIFBenchSuite(unittest.TestCase): + def test_suite_registered(self) -> None: + suite = get_suite("ifbench") + self.assertEqual( + tuple(suite.tasks), + ( + "ifeval_mt_wildchat_unused_withRewrite", + "ifeval_mt_ood_wildchat_unused_withRewrite", + "ifeval_ood", + ), + ) + + +class TestIFEvalScorer(unittest.TestCase): + """Use ``count:numbers`` (must include exactly N digits) — a deterministic verifier.""" + + INSTRUCTION_ID = "count:numbers" + KWARGS: dict[str, Any] = {"N": 2} + + def _score(self, response_text: str) -> dict[str, list[bool]]: + instance = _make_instance( + "Include exactly 2 numbers.", [self.INSTRUCTION_ID], [self.KWARGS] + ) + output = LMOutput(text=response_text) + IFEvalScorer().score(instance, output) + return output.metadata["ifeval"] + + def test_satisfied(self) -> None: + result = self._score("I have 3 apples and 4 oranges.") + self.assertEqual(result["strict"], [True]) + self.assertEqual(result["loose"], [True]) + + def test_violated_too_few(self) -> None: + result = self._score("I have apples and oranges.") + self.assertEqual(result["strict"], [False]) + self.assertEqual(result["loose"], [False]) + + def test_violated_too_many(self) -> None: + result = self._score("I have 1 apple, 2 oranges, and 3 grapes.") + self.assertEqual(result["strict"], [False]) + self.assertEqual(result["loose"], [False]) + + def test_loose_strips_leading_line(self) -> None: + # Strict fails: leading "Sure!" line adds no number, body has 2. + # But loose strips first line, leaving exactly 2 — passes. + result = self._score( + "Sure! Here's a response with 5 trailing extras at the end.\n" + "I have 3 apples and 4 oranges." + ) + self.assertEqual(result["strict"], [False]) + self.assertEqual(result["loose"], [True]) + + +class TestIFEvalMetrics(unittest.TestCase): + INSTRUCTION_ID = "count:numbers" + KWARGS: dict[str, Any] = {"N": 2} + + def _scored_response(self, response_text: str) -> Response: + instance = _make_instance("count.", [self.INSTRUCTION_ID], [self.KWARGS]) + response = _make_response(instance, response_text) + IFEvalScorer().score(instance, response.outputs[0]) + return response + + def test_aggregation(self) -> None: + responses = [ + self._scored_response("I have 3 apples and 4 oranges."), # passes + self._scored_response("Just words, no digits."), # fails + ] + self.assertAlmostEqual(IFEvalPromptStrictAccuracy().compute(responses), 0.5) + self.assertAlmostEqual(IFEvalPromptLooseAccuracy().compute(responses), 0.5) + self.assertAlmostEqual(IFEvalInstStrictAccuracy().compute(responses), 0.5) + self.assertAlmostEqual(IFEvalInstLooseAccuracy().compute(responses), 0.5) + + def test_multi_instruction_prompt_requires_all(self) -> None: + instance = _make_instance( + "Two numbers and an emoji-terminated sentence.", + ["count:numbers", "format:emoji"], + [{"N": 2}, {}], + ) + # Has 2 numbers (passes count) but no emoji at end of sentence (fails emoji). + response = _make_response(instance, "I have 3 apples and 4 oranges.") + IFEvalScorer().score(instance, response.outputs[0]) + prompt_acc = IFEvalPromptStrictAccuracy().compute([response]) + inst_acc = IFEvalInstStrictAccuracy().compute([response]) + self.assertEqual(prompt_acc, 0.0) # not all instructions satisfied + self.assertEqual(inst_acc, 0.5) # 1 of 2 satisfied + + +if __name__ == "__main__": + unittest.main() diff --git a/uv.lock b/uv.lock index d673a4c76..aafb5a876 100644 --- a/uv.lock +++ b/uv.lock @@ -50,6 +50,15 @@ conflicts = [[ [manifest] overrides = [{ name = "transformers", specifier = ">=5.4.0" }] +[[package]] +name = "absl-py" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, +] + [[package]] name = "aiofile" version = "3.9.0" @@ -1906,6 +1915,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] +[[package]] +name = "emoji" +version = "2.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/78/0d2db9382c92a163d7095fc08efff7800880f830a152cfced40161e7638d/emoji-2.15.0.tar.gz", hash = "sha256:eae4ab7d86456a70a00a985125a03263a5eac54cd55e51d7e184b1ed3b6757e4", size = 615483, upload-time = "2025-09-21T12:13:02.755Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/5e/4b5aaaabddfacfe36ba7768817bd1f71a7a810a43705e531f3ae4c690767/emoji-2.15.0-py3-none-any.whl", hash = "sha256:205296793d66a89d88af4688fa57fd6496732eb48917a87175a023c8138995eb", size = 608433, upload-time = "2025-09-21T12:13:01.197Z" }, +] + [[package]] name = "et-xmlfile" version = "2.0.0" @@ -3092,6 +3110,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, ] +[[package]] +name = "ifbench" +version = "0.2.0" +source = { git = "https://github.com/allenai/IFBench.git?rev=finbarr%2Fclean-install#b281f8d4dae7f4defffe737472b3e79c042b6705" } +dependencies = [ + { name = "absl-py" }, + { name = "emoji" }, + { name = "httpx" }, + { name = "immutabledict" }, + { name = "langdetect" }, + { name = "nltk" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "setuptools" }, + { name = "syllapy" }, + { name = "tqdm" }, + { name = "unicodedata2" }, +] + [[package]] name = "ijson" version = "3.5.0" @@ -3155,6 +3192,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/23/28/96711503245339084c8086b892c47415895eba49782d6cc52d9f4ee50301/ijson-3.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4f24b78d4ef028d17eb57ad1b16c0aed4a17bdd9badbf232dc5d9305b7e13854", size = 58965, upload-time = "2026-02-24T03:58:11.278Z" }, ] +[[package]] +name = "immutabledict" +version = "4.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/e6/718471048fea0366c3e3d1df3acfd914ca66d571cdffcf6d37bbcd725708/immutabledict-4.3.1.tar.gz", hash = "sha256:f844a669106cfdc73f47b1a9da003782fb17dc955a54c80972e0d93d1c63c514", size = 7806, upload-time = "2026-02-15T10:32:34.668Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/ce/f9018bf69ae91b273b6391a095e7c93fa5e1617f25b6ba81ad4b20c9df10/immutabledict-4.3.1-py3-none-any.whl", hash = "sha256:c9facdc0ff30fdb8e35bd16532026cac472a549e182c94fa201b51b25e4bf7bf", size = 5000, upload-time = "2026-02-15T10:32:33.672Z" }, +] + [[package]] name = "importlib-metadata" version = "8.7.1" @@ -3799,6 +3845,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/70/05b685ea2dffcb2adbf3cdcea5d8865b7bc66f67249084cf845012a0ff13/kubernetes-35.0.0-py2.py3-none-any.whl", hash = "sha256:39e2b33b46e5834ef6c3985ebfe2047ab39135d41de51ce7641a7ca5b372a13d", size = 2017602, upload-time = "2026-01-16T01:05:25.991Z" }, ] +[[package]] +name = "langdetect" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } + [[package]] name = "lark" version = "1.2.2" @@ -4395,7 +4450,7 @@ dependencies = [ { name = "httpx", marker = "sys_platform != 'darwin'" }, { name = "jmespath", marker = "sys_platform != 'darwin'" }, { name = "pydantic", marker = "sys_platform != 'darwin'" }, - { name = "setuptools", version = "80.10.2", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'darwin'" }, + { name = "setuptools", marker = "sys_platform != 'darwin'" }, { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'darwin'" }, { name = "supervisor", marker = "sys_platform != 'darwin'" }, ] @@ -4747,6 +4802,21 @@ wheels = [ { 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]] +name = "nltk" +version = "3.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "joblib" }, + { name = "regex" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/a1/b3b4adf15585a5bc4c357adde150c01ebeeb642173ded4d871e89468767c/nltk-3.9.4.tar.gz", hash = "sha256:ed03bc098a40481310320808b2db712d95d13ca65b27372f8a403949c8b523d0", size = 2946864, upload-time = "2026-03-24T06:13:40.641Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/91/04e965f8e717ba0ab4bdca5c112deeab11c9e750d94c4d4602f050295d39/nltk-3.9.4-py3-none-any.whl", hash = "sha256:f2fa301c3a12718ce4a0e9305c5675299da5ad9e26068218b69d692fda84828f", size = 1552087, upload-time = "2026-03-24T06:13:38.47Z" }, +] + [[package]] name = "nodeenv" version = "1.10.0" @@ -5150,11 +5220,13 @@ source = { editable = "." } dependencies = [ { name = "click" }, { name = "datasets" }, + { name = "ifbench" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(sys_platform != 'darwin' and extra == 'extra-18-olmo-eval-internal-agents') or (sys_platform != 'darwin' and extra == 'extra-18-olmo-eval-internal-clients') or (sys_platform != 'darwin' and extra != 'extra-18-olmo-eval-internal-openhands') or (extra == 'extra-18-olmo-eval-internal-agents' and extra == 'extra-18-olmo-eval-internal-openhands') or (extra == 'extra-18-olmo-eval-internal-clients' and extra == 'extra-18-olmo-eval-internal-openhands') or (extra == 'extra-18-olmo-eval-internal-openhands' and extra == 'extra-18-olmo-eval-internal-vllm')" }, { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform == 'darwin' or extra == 'extra-18-olmo-eval-internal-openhands'" }, { name = "omegaconf" }, { name = "prometheus-client" }, { name = "rich" }, + { name = "setuptools" }, { name = "sympy" }, { name = "textual-plot" }, { name = "tree-sitter" }, @@ -5241,6 +5313,7 @@ requires-dist = [ { name = "click", specifier = "~=8.3.2" }, { name = "datasets", specifier = ">=3.2.0" }, { name = "httpx", marker = "extra == 'agents'", specifier = "~=0.28.1" }, + { name = "ifbench", git = "https://github.com/allenai/IFBench.git?rev=finbarr%2Fclean-install" }, { name = "litellm", marker = "extra == 'litellm'", specifier = "~=1.80.11" }, { name = "matplotlib", marker = "extra == 'analysis'", specifier = "~=3.10.8" }, { name = "numpy", specifier = ">=1.20.0" }, @@ -5256,6 +5329,7 @@ requires-dist = [ { name = "rich", specifier = "~=14.3.4" }, { name = "scipy", marker = "extra == 'analysis'", specifier = "~=1.17.1" }, { name = "seaborn", marker = "extra == 'analysis'", specifier = "~=0.13.2" }, + { name = "setuptools", specifier = "<81" }, { name = "smart-open", extras = ["s3"], marker = "extra == 's3'", specifier = ">=7.0.0" }, { name = "sqlalchemy", marker = "extra == 'postgres'", specifier = ">=2.0.49" }, { name = "swe-rex", extras = ["modal"], marker = "extra == 'sandbox'", git = "https://github.com/jdahm/SWE-ReX.git?rev=johannd%2Fai2" }, @@ -5562,7 +5636,7 @@ dependencies = [ { name = "rapidfuzz" }, { name = "redis" }, { name = "requests" }, - { name = "setuptools", version = "82.0.1", source = { registry = "https://pypi.org/simple" } }, + { name = "setuptools" }, { name = "shellingham" }, { name = "sqlalchemy", extra = ["asyncio"], marker = "extra == 'extra-18-olmo-eval-internal-openhands'" }, { name = "sse-starlette" }, @@ -6960,9 +7034,9 @@ name = "pydantic-settings" version = "2.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydantic", marker = "sys_platform != 'darwin' or extra == 'extra-18-olmo-eval-internal-agents' or extra == 'extra-18-olmo-eval-internal-openhands'" }, - { name = "python-dotenv", marker = "sys_platform != 'darwin' or extra == 'extra-18-olmo-eval-internal-agents' or extra == 'extra-18-olmo-eval-internal-openhands'" }, - { name = "typing-inspection", marker = "sys_platform != 'darwin' or extra == 'extra-18-olmo-eval-internal-agents' or extra == 'extra-18-olmo-eval-internal-openhands'" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/98/c8345dccdc31de4228c039a98f6467a941e39558da41c1744fbe29fa5666/pydantic_settings-2.14.0.tar.gz", hash = "sha256:24285fd4b0e0c06507dd9fdfd331ee23794305352aaec8fc4eb92d4047aeb67d", size = 235709, upload-time = "2026-04-20T13:37:40.293Z" } wheels = [ @@ -11035,42 +11109,11 @@ wheels = [ name = "setuptools" version = "80.10.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.13' and sys_platform == 'win32'", - "python_full_version < '3.13' and sys_platform == 'emscripten'", - "python_full_version < '3.13' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] sdist = { url = "https://files.pythonhosted.org/packages/76/95/faf61eb8363f26aa7e1d762267a8d602a1b26d4f3a1e758e92cb3cb8b054/setuptools-80.10.2.tar.gz", hash = "sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70", size = 1200343, upload-time = "2026-01-25T22:38:17.252Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173", size = 1064234, upload-time = "2026-01-25T22:38:15.216Z" }, ] -[[package]] -name = "setuptools" -version = "82.0.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.13' and sys_platform == 'win32'", - "python_full_version < '3.13' and sys_platform == 'emscripten'", - "python_full_version < '3.13' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, -] - [[package]] name = "shellingham" version = "1.5.4" @@ -11344,6 +11387,15 @@ modal = [ { name = "modal" }, ] +[[package]] +name = "syllapy" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/a1/7bc1ce4852e14ab5f3153262639742ae63fbfa626507dac4ab919a1e5232/syllapy-0.7.2.tar.gz", hash = "sha256:e55a7ad97d8b232e174b83f91b8f9be0c355d2a8e1208c7f6229055189605564", size = 25561, upload-time = "2022-08-29T01:55:03.366Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/cc/ffc9bddc146f14e8792a9b05b2bd1bc5f23f3b752a06e96b244780ce55b9/syllapy-0.7.2-py3-none-any.whl", hash = "sha256:198a7413033c32d7b31e21962efb3f284bcea80d3346e954b938ca1ebe6bee20", size = 24882, upload-time = "2022-08-29T01:55:01.1Z" }, +] + [[package]] name = "sympy" version = "1.14.0" @@ -11646,7 +11698,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "setuptools", version = "80.10.2", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'darwin'" }, + { name = "setuptools", marker = "sys_platform != 'darwin'" }, { name = "sympy", marker = "sys_platform != 'darwin'" }, { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "typing-extensions", marker = "sys_platform != 'darwin'" }, @@ -12072,6 +12124,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/e1/7ec67882ad8fc9f86384bef6421fa252c9cbe5744f8df6ce77afc9eca1f5/uncalled_for-0.3.1-py3-none-any.whl", hash = "sha256:074cdc92da8356278f93d0ded6f2a66dd883dbecaf9bc89437646ee2289cc200", size = 11361, upload-time = "2026-04-07T13:05:05.341Z" }, ] +[[package]] +name = "unicodedata2" +version = "17.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cb/520721a715da85530e21c71953b9b9a85a44e0d80d3b34bf9303c422d208/unicodedata2-17.0.1.tar.gz", hash = "sha256:d79943d153f5f6bfbe3f55a5ec611985184bda37fcedb3ecc75322d82ae6ad3b", size = 679856, upload-time = "2026-02-12T10:05:41.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/7b/52359e301fe53fc742e1f9ef8b2aec4b8b0d5509c365eb1819072a46506e/unicodedata2-17.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4bd5990d17c8415ed44d4cb2642a06c0377551540d151c458dcdff5426719661", size = 973395, upload-time = "2026-02-12T10:04:29.234Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b8/d2140512697cd1085b2a7004cd7813c1e6b26033587f19aa5f02ab25a54a/unicodedata2-17.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cbc1d0a458294ae5af4a7ca560dae976a6a88534fc2c61289f0b8ab25684aeb1", size = 495277, upload-time = "2026-02-12T10:04:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/56/f5/17f8ad3a780043d2aff2b8bbb60280ecebc54cf45596942942fae28cd33d/unicodedata2-17.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88a32dc5372787f9cc0bfaf0a39b38a72e3f703111efa84a550cc228b85f2a30", size = 531996, upload-time = "2026-02-12T10:04:32.274Z" }, + { url = "https://files.pythonhosted.org/packages/32/b5/f1ef0d3944f30ebc0fc436a5be98e53969d76f975ce1005aeb5d99acc7be/unicodedata2-17.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b9cceda1f25498670245c79a6a1b3e2bc310b629693934075c388cc02585a686", size = 531920, upload-time = "2026-02-12T10:04:33.617Z" }, + { url = "https://files.pythonhosted.org/packages/0b/d0/837bec637a3076496627d24d9921f7b5855122e2558d25417f1146f9e63f/unicodedata2-17.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c9eee5d5bad5ced178f14d946f106dff4419cb76000b77b49bc78b50fabe7b36", size = 530573, upload-time = "2026-02-12T10:04:35.17Z" }, + { url = "https://files.pythonhosted.org/packages/1d/89/c73a4e430d59d80f9e07ffb85294cfcb47c5050249728b1049e7b51ed351/unicodedata2-17.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9e01d1525f57695fbb4aed3efad8814ae6fdbb9a0b710ec9dec18d1b07dd2f0", size = 531410, upload-time = "2026-02-12T10:04:36.631Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f7/731641438894f9c11e5281b6ebb7cc01467565c4a63e2c9be72a0d0dd741/unicodedata2-17.0.1-cp312-cp312-win32.whl", hash = "sha256:fd6d360f2063547e9ed8e01e9335bbc0fe0b71dd19649a614a76acb37e72eba4", size = 483974, upload-time = "2026-02-12T10:04:38.145Z" }, + { url = "https://files.pythonhosted.org/packages/dd/4d/24523557cfd632fc70fc031a83b280ae60d618e55afd54a6298c5d8b80f7/unicodedata2-17.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:d1439ad3ee0daace878196de4466a86aa5015cb244b9b1d5d00db74344649722", size = 484194, upload-time = "2026-02-12T10:04:39.856Z" }, + { url = "https://files.pythonhosted.org/packages/4e/93/b30e22fc5c06827a112bf399fa9d583ccd3209ae5b6bb9fa101823d85cc3/unicodedata2-17.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e700dbedf1ec4466e1f36d2172fa2c856141e8d8ee256f5d1ef32507f7afa2b8", size = 973390, upload-time = "2026-02-12T10:04:41.854Z" }, + { url = "https://files.pythonhosted.org/packages/6b/71/61d7694139f62e9bbfc9d51c36e1fb7ce578d530074a75573ca59fb76c97/unicodedata2-17.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc83524357ea99933ff0b33eb781f35381b6da0e89fb466bbfd9e52d3b701602", size = 495284, upload-time = "2026-02-12T10:04:43.184Z" }, + { url = "https://files.pythonhosted.org/packages/67/c8/4a227db7c366c10e6135dc53c7389060f295ae234e696ae41406ace2c92c/unicodedata2-17.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3aefd1fd71d95e87ba8df580f54ae4d52076e4394eddc97d0f4609849f01ae4", size = 531970, upload-time = "2026-02-12T10:04:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/ae/62/4dfe56801216acfff25c07a68d2a0b5330e802fbd1f89cf8ba4ae3374b2e/unicodedata2-17.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8a4c70a9b1438b2303ab577c6c3a80c650952c76f496418ef7ab6755ff1ffbea", size = 531750, upload-time = "2026-02-12T10:04:45.952Z" }, + { url = "https://files.pythonhosted.org/packages/4a/eb/c078cc851bf3212e56711bbd56e63579645f9a2d14cc1aa04397b90ba552/unicodedata2-17.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:761c53084ca0f3a1beda52f1c3980a0d561221f860a56a1342087c67879fd547", size = 530549, upload-time = "2026-02-12T10:04:47.83Z" }, + { url = "https://files.pythonhosted.org/packages/a5/c9/f95deb4a197bdd9af29bcbd8091a9847431ca16fcc5f9981efcdbe0e057e/unicodedata2-17.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ba5f094d6ff67c130fe36fbdad64371c7b2e7672f4e35166f98ae6c88646ccda", size = 531457, upload-time = "2026-02-12T10:04:49.254Z" }, + { url = "https://files.pythonhosted.org/packages/30/f6/de84a37d8fbbb2cd57ce6b6ba1af8bba9ffbecd05c046630e47629e74147/unicodedata2-17.0.1-cp313-cp313-win32.whl", hash = "sha256:e314cd8a8f64aa0d2bcf940b9d8e742cb726566574bf241a02b23d0ea9c779c9", size = 483971, upload-time = "2026-02-12T10:04:51.11Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7e/94116c542f4348b2def3e34654b4e1af66862e93e884c7405b361c6e92d6/unicodedata2-17.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:7ec69751488663ad5644b2bce67be9bbf9a178ba9ad3089ca652b05cf5a2aa49", size = 484193, upload-time = "2026-02-12T10:04:52.585Z" }, + { url = "https://files.pythonhosted.org/packages/1c/37/abd5d5babb5d7a898c06b3f4635a81741beae0ff96986ef2656614bb4cb9/unicodedata2-17.0.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6ac68ff0d4d8a1c1ccece9a29f5c2dd34c456a6ef5631eea7d926cbf288be3c7", size = 973471, upload-time = "2026-02-12T10:04:53.984Z" }, + { url = "https://files.pythonhosted.org/packages/44/41/749dfd9ebef778425a0d1b3bdd47d70413743d0df8e618663db930071122/unicodedata2-17.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9a8e82d999809157006c8f5942ef86d980d770798f77bffa6ec1c99150bfe1f0", size = 495320, upload-time = "2026-02-12T10:04:55.498Z" }, + { url = "https://files.pythonhosted.org/packages/08/90/7c929314a0fe1a867f795d220148bef7943db9a462e68ec9332cdf6402b4/unicodedata2-17.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21c3307f72d85b4e886037f100dc1ea10fddaea4086d81136712a1b7c278ec1d", size = 531904, upload-time = "2026-02-12T10:04:57.067Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b1/fcc2231f554f6c2d2b2132b6e4d3526e81961b0ad1593dd869872de0f75e/unicodedata2-17.0.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:730c3e33320dcfbafd6b1e91d5233a07d5c44f3ff713c0c16d76f72debeb0ac4", size = 531691, upload-time = "2026-02-12T10:04:58.4Z" }, + { url = "https://files.pythonhosted.org/packages/df/00/b06450a610c53a6e2aa3ca9bcf6863028b6c95700a3b0b99ab31c77b00ca/unicodedata2-17.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0d1c9efe0380568b68efc6620b3b5780845b17a1bd916b27c890a4d4a80f8078", size = 530495, upload-time = "2026-02-12T10:04:59.831Z" }, + { url = "https://files.pythonhosted.org/packages/14/04/35df12e1febace8696311bf5f8800172831885340e9d58b2ab6e59a70364/unicodedata2-17.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:410d6461ff1a98bea61c960a993e19ac60cff878e0d7774cc0c9ad6a60409f92", size = 531388, upload-time = "2026-02-12T10:05:01.376Z" }, + { url = "https://files.pythonhosted.org/packages/86/89/e42e4a6243c0c28bc9598ad3694d32be1f171fa95fb3a652aa64e45e119f/unicodedata2-17.0.1-cp314-cp314-win32.whl", hash = "sha256:4dd637b5ea44fd215e6fccf4111b6b8b8895da8e869fbb90e20626f54afee9bb", size = 577494, upload-time = "2026-02-12T10:05:03.339Z" }, + { url = "https://files.pythonhosted.org/packages/d2/08/7442582477e909de2312e76ebe9ce61c84594ce068429da7bdc6ba865e35/unicodedata2-17.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:6c085978d6e655716ba606f736bf1e7f957fa3a3f56df5e5d6aa87b4d1cb9ca0", size = 577747, upload-time = "2026-02-12T10:05:04.817Z" }, + { url = "https://files.pythonhosted.org/packages/ec/95/0b3e8da4a09b8985e20a5ececf6c58e94c9a9ebf34a9d18a85a0c703d50e/unicodedata2-17.0.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d4e40a701508e705b52f4df0d41f9cccf6eaa1160bb92b52348c98341b508461", size = 973976, upload-time = "2026-02-12T10:05:06.973Z" }, + { url = "https://files.pythonhosted.org/packages/67/55/4576286b7a89378d237fb140aa7474f1f2dcbf3cf6e4f14766b5aadefe11/unicodedata2-17.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b05a1469280f94e8fbc022563b6751a8a30640361ec2c6de4f73e7f5f6c9db6b", size = 495694, upload-time = "2026-02-12T10:05:08.915Z" }, + { url = "https://files.pythonhosted.org/packages/ab/aa/bf2da5223c5a016bc2975add15524ec08d860142ccecb4951143ba04c453/unicodedata2-17.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5800972e1aefd6da8f4661b389f095249f0ff63530bc2a3fbabf00d2b3b52b6", size = 533692, upload-time = "2026-02-12T10:05:10.286Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/fb8d97881b5289e551425a8e36391d7633f83dea29b4c3374fa574927b86/unicodedata2-17.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d7cd7d058be81fce6e62dbcb8b1f8eddf77407f82fb108fb5ca4b4623bdb5beb", size = 533415, upload-time = "2026-02-12T10:05:11.941Z" }, + { url = "https://files.pythonhosted.org/packages/4e/0f/7bb66d630a050c78350a2e689ecf76b3c9fd4108df4fd30545465361d317/unicodedata2-17.0.1-cp314-cp314t-win32.whl", hash = "sha256:164867ee8d64b2eb62e1b9e3fbc21eb6d3d99d7c491888eebb45a5131d49fc6c", size = 577672, upload-time = "2026-02-12T10:05:13.819Z" }, + { url = "https://files.pythonhosted.org/packages/15/ff/6c5a0f561eeb47cd09f20caebc0416ec1d253b68cc7264a85f420b6350eb/unicodedata2-17.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:31647c7ff10197487d60a1bbb92d13a095c87e5ca3e1c218510e5cce39b2de21", size = 578003, upload-time = "2026-02-12T10:05:15.249Z" }, +] + [[package]] name = "uri-template" version = "1.3.0" @@ -12237,7 +12327,7 @@ dependencies = [ { name = "requests", marker = "sys_platform != 'darwin'" }, { name = "sentencepiece", marker = "sys_platform != 'darwin'" }, { name = "setproctitle", marker = "sys_platform != 'darwin'" }, - { name = "setuptools", version = "80.10.2", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'darwin'" }, + { name = "setuptools", marker = "sys_platform != 'darwin'" }, { name = "six", marker = "sys_platform != 'darwin'" }, { name = "tiktoken", marker = "sys_platform != 'darwin'" }, { name = "tokenizers", marker = "sys_platform != 'darwin'" }, @@ -12822,7 +12912,7 @@ name = "zope-interface" version = "7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "setuptools", version = "82.0.1", source = { registry = "https://pypi.org/simple" } }, + { name = "setuptools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/30/93/9210e7606be57a2dfc6277ac97dcc864fd8d39f142ca194fdc186d596fda/zope.interface-7.2.tar.gz", hash = "sha256:8b49f1a3d1ee4cdaf5b32d2e738362c7f5e40ac8b46dd7d1a65e82a4872728fe", size = 252960, upload-time = "2024-11-28T08:45:39.224Z" } wheels = [