diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a39054e37..31a0a2586 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,6 +24,8 @@ jobs: activate-environment: true # Activate for simple `uv sync` below - run: uv sync - uses: j178/prek-action@v1 + with: + prek-version: 0.2.14 # Downpin for https://github.com/j178/prek/issues/1104 - uses: pre-commit-ci/lite-action@v1.1.0 if: always() lint: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6455a6dca..b749e7253 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,8 +82,9 @@ repos: rev: v1.18.1 hooks: - id: jupytext - args: [--to, md, --pipe, black] - additional_dependencies: [black<25.11.0] # Downpin for https://github.com/mwouts/jupytext/issues/1467 + # SEE: https://github.com/mwouts/jupytext/issues/1467 + args: [--to, md, --pipe-fmt, ipynb, --pipe, "black {}"] + additional_dependencies: [black] files: ^docs/.*\.ipynb$ - repo: https://github.com/jsh9/markdown-toc-creator rev: 0.1.3 diff --git a/pyproject.toml b/pyproject.toml index e2ace7a6e..bceb67dbb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ classifiers = [ dependencies = [ "anyio", "fhaviary[llm]>=0.27", # For partial tool concurrency - "fhlmi>=0.40.1", # Pin for new llm router calling syntax + "fhlmi>=0.41.0", # Pin for LiteLLMModel.get_router "html2text", # TODO: evaluate moving to an opt-in dependency "httpx", "httpx-aiohttp", @@ -64,7 +64,7 @@ dev = [ "litellm>=1.71", # Lower pin for aiohttp transport adoption "mypy>=1.8", # Pin for mutable-override "paper-qa[docling,image,ldp,memory,pypdf-media,pymupdf,typing,zotero,local,qdrant,office]", - "prek", + "prek<0.2.15", # Downpin for https://github.com/j178/prek/issues/1104 "pydantic~=2.11", # Pin for start of model_fields deprecation "pylint-pydantic", "pytest-asyncio", diff --git a/src/paperqa/settings.py b/src/paperqa/settings.py index 0bc331030..652da2dc6 100644 --- a/src/paperqa/settings.py +++ b/src/paperqa/settings.py @@ -1111,7 +1111,7 @@ def make_aviary_tool_selector(self, agent_type: str | type) -> ToolSelector | No ): return ToolSelector( model_name=self.agent.agent_llm, - acompletion=self.get_agent_llm().router().acompletion, + acompletion=self.get_agent_llm().get_router().acompletion, **(self.agent.agent_config or {}), ) return None diff --git a/src/paperqa/types.py b/src/paperqa/types.py index 97dc0d012..a7b80dbe7 100644 --- a/src/paperqa/types.py +++ b/src/paperqa/types.py @@ -394,14 +394,14 @@ def add_tokens(self, result: LLMResult | Message) -> None: prompt_count=result.info["usage"][0], completion_count=result.info["usage"][1], ) + + prompt_count = result.prompt_count or 0 + completion_count = result.completion_count or 0 if result.model not in self.token_counts: - self.token_counts[result.model] = [ - result.prompt_count, - result.completion_count, - ] + self.token_counts[result.model] = [prompt_count, completion_count] else: - self.token_counts[result.model][0] += result.prompt_count - self.token_counts[result.model][1] += result.completion_count + self.token_counts[result.model][0] += prompt_count + self.token_counts[result.model][1] += completion_count self.cost += result.cost diff --git a/tests/test_paperqa.py b/tests/test_paperqa.py index bf55ae3ef..c25fa1fd1 100644 --- a/tests/test_paperqa.py +++ b/tests/test_paperqa.py @@ -447,7 +447,9 @@ def accum(x) -> None: assert isinstance(first_id, UUID) assert completion.text assert completion.seconds_to_first_token > 0 + assert completion.prompt_count is not None assert completion.prompt_count > 0 + assert completion.completion_count is not None assert completion.completion_count > 0 assert completion.model == "babbage-002" assert str(completion) == "".join(outputs) @@ -461,7 +463,9 @@ def accum(x) -> None: assert completion.text assert completion.seconds_to_first_token == 0 assert completion.seconds_to_last_token > 0 + assert completion.prompt_count is not None assert completion.prompt_count > 0 + assert completion.completion_count is not None assert completion.completion_count > 0 try: assert completion.model == "babbage-002" @@ -469,7 +473,7 @@ def accum(x) -> None: except AssertionError: # Account for https://github.com/BerriAI/litellm/issues/10572 assert any( - "Could not find cost for model".lower() in r.message.lower() + "Failed to calculate cost".lower() in r.message.lower() for r in caplog.records ) @@ -492,7 +496,9 @@ def accum(x) -> None: callbacks=[accum], ) assert completion.seconds_to_first_token > 0 + assert completion.prompt_count is not None assert completion.prompt_count > 0 + assert completion.completion_count is not None assert completion.completion_count > 0 assert str(completion) == "".join(outputs) assert isinstance(completion.text, str) diff --git a/uv.lock b/uv.lock index cdddbba1e..fc0b8ee51 100644 --- a/uv.lock +++ b/uv.lock @@ -968,7 +968,7 @@ llm = [ [[package]] name = "fhlmi" -version = "0.40.1" +version = "0.41.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coredis" }, @@ -979,9 +979,9 @@ dependencies = [ { name = "tiktoken" }, { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/15/7e/e390a14f10d4a3d3df2ea33f785b62b423b58d2ccd8b4448c4ce1c9e5670/fhlmi-0.40.1.tar.gz", hash = "sha256:5225fbc4ed1ab0fdef5491d24f523a8cc30fc3329d8dee99d56dcd1d0ef8196a", size = 402903, upload-time = "2025-11-10T18:45:17.513Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/32/e28a991580aefdd6e384bd43b2c4a416f4c2ce19ac7cf57421ee64167e22/fhlmi-0.41.0.tar.gz", hash = "sha256:7a04391798fd169784d8dc54f034357347e9e31b4515316409aa31776b7788d1", size = 420990, upload-time = "2025-11-12T23:59:48.423Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/1f/039e158438666eb7cf3a1c3e34447ca42cae820f2dd6b0bc6f28e20340e8/fhlmi-0.40.1-py3-none-any.whl", hash = "sha256:0d24367d7913a3fa615160e8064104714c48418a861986af6a71d63d0398b0a8", size = 42975, upload-time = "2025-11-10T18:45:16.357Z" }, + { url = "https://files.pythonhosted.org/packages/54/54/c765f06db4d32c6bb2b61a5d68f5ddf03a3f138cbc7bdddc5adac7cea760/fhlmi-0.41.0-py3-none-any.whl", hash = "sha256:930abf4fcf7bde655ba6224578e9030d74e10798c759280e075f1b450f1f95cb", size = 43896, upload-time = "2025-11-12T23:59:47.087Z" }, ] [package.optional-dependencies] @@ -2380,7 +2380,7 @@ name = "nvidia-cudnn-cu12" version = "9.10.2.21" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, @@ -2391,7 +2391,7 @@ name = "nvidia-cufft-cu12" version = "11.3.3.83" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, @@ -2418,9 +2418,9 @@ name = "nvidia-cusolver-cu12" version = "11.7.3.90" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12" }, - { name = "nvidia-cusparse-cu12" }, - { name = "nvidia-nvjitlink-cu12" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, @@ -2431,7 +2431,7 @@ name = "nvidia-cusparse-cu12" version = "12.5.8.93" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, @@ -2482,9 +2482,9 @@ name = "ocrmac" version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "pillow" }, - { name = "pyobjc-framework-vision" }, + { name = "click", marker = "sys_platform == 'darwin'" }, + { name = "pillow", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-vision", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/dc/de3e9635774b97d9766f6815bbb3f5ec9bce347115f10d9abbf2733a9316/ocrmac-1.0.0.tar.gz", hash = "sha256:5b299e9030c973d1f60f82db000d6c2e5ff271601878c7db0885e850597d1d2e", size = 1463997, upload-time = "2024-11-07T12:00:00.197Z" } wheels = [ @@ -2554,7 +2554,7 @@ name = "opencv-python-headless" version = "4.11.0.86" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", marker = "python_full_version >= '3.14' and python_full_version < '4'" }, + { name = "numpy" }, ] sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" } wheels = [ @@ -2775,7 +2775,7 @@ dev = [ requires-dist = [ { name = "anyio" }, { name = "fhaviary", extras = ["llm"], specifier = ">=0.27" }, - { name = "fhlmi", specifier = ">=0.40.1" }, + { name = "fhlmi", specifier = ">=0.41.0" }, { name = "fhlmi", extras = ["image"], marker = "extra == 'image'" }, { name = "html2text" }, { name = "httpx" }, @@ -2795,7 +2795,7 @@ requires-dist = [ { name = "paper-qa-pypdf", editable = "packages/paper-qa-pypdf" }, { name = "paper-qa-pypdf", marker = "extra == 'pypdf'", editable = "packages/paper-qa-pypdf" }, { name = "paper-qa-pypdf", extras = ["media"], marker = "extra == 'pypdf-media'", editable = "packages/paper-qa-pypdf" }, - { name = "prek", marker = "extra == 'dev'" }, + { name = "prek", marker = "extra == 'dev'", specifier = "<0.2.15" }, { name = "pybtex" }, { name = "pydantic", specifier = "~=2.0,>=2.10.1" }, { name = "pydantic", marker = "extra == 'dev'", specifier = "~=2.11" }, @@ -3600,7 +3600,7 @@ name = "pyobjc-framework-cocoa" version = "12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/37/6f/89837da349fe7de6476c426f118096b147de923139556d98af1832c64b97/pyobjc_framework_cocoa-12.0.tar.gz", hash = "sha256:02d69305b698015a20fcc8e1296e1528e413d8cf9fdcd590478d359386d76e8a", size = 2771906, upload-time = "2025-10-21T08:30:51.765Z" } wheels = [ @@ -3617,8 +3617,8 @@ name = "pyobjc-framework-coreml" version = "12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0c/a0/875b5174794c984df60944be54df0282945f8bae4a606fbafa0c6b717ddd/pyobjc_framework_coreml-12.0.tar.gz", hash = "sha256:e1d7a9812886150881c86000fba885cb15201352c75fb286bd9e3a1819b5a4d5", size = 40814, upload-time = "2025-10-21T08:31:53.83Z" } wheels = [ @@ -3635,8 +3635,8 @@ name = "pyobjc-framework-quartz" version = "12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/0b/3c34fc9de790daff5ca49d1f36cb8dcc353ac10e4e29b4759e397a3831f4/pyobjc_framework_quartz-12.0.tar.gz", hash = "sha256:5bcb9e78d671447e04d89e2e3c39f3135157892243facc5f8468aa333e40d67f", size = 3159509, upload-time = "2025-10-21T08:40:01.918Z" } wheels = [ @@ -3653,10 +3653,10 @@ name = "pyobjc-framework-vision" version = "12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreml" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreml", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/5a/07cdead5adb77d0742b014fa742d503706754e3ad10e39760e67bb58b497/pyobjc_framework_vision-12.0.tar.gz", hash = "sha256:942c9583f1d887ac9f704f3b0c21b3206b68e02852a87219db4309bb13a02f14", size = 59905, upload-time = "2025-10-21T08:41:53.741Z" } wheels = [