From 5f63873dcad12d0aee51eabc974273eda5278205 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 00:05:39 -0700 Subject: [PATCH 01/32] [Infra] Pin all Docker build dependencies to exact versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pin every dependency across all Docker builds so upgrades are intentional. Verified by building all 3 production images and diffing pip freeze against known-good v1.83.0-nightly baselines — zero version drift. Co-Authored-By: Claude Opus 4.6 (1M context) --- Dockerfile | 8 +- deploy/Dockerfile.ghcr_base | 2 +- docker/Dockerfile.alpine | 8 +- docker/Dockerfile.custom_ui | 5 +- docker/Dockerfile.database | 8 +- docker/Dockerfile.dev | 8 +- docker/Dockerfile.health_check | 10 +- docker/Dockerfile.non_root | 16 +- .../build_from_pip/Dockerfile.build_from_pip | 4 +- docker/build_from_pip/requirements.txt | 10 +- docker/install_auto_router.sh | 2 +- pyproject.toml | 167 +++++++++--------- requirements.txt | 37 ++-- .../health_check_requirements.txt | 4 +- 14 files changed, 154 insertions(+), 135 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7bda32acf27..07481f2b0e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ # Base image for building -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502 # Runtime image -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502 # Builder stage FROM $LITELLM_BUILD_IMAGE AS builder @@ -15,7 +15,7 @@ USER root # Install build dependencies RUN apk add --no-cache bash gcc py3-pip python3 python3-dev openssl openssl-dev -RUN python -m pip install build +RUN python -m pip install build==1.4.2 # Copy the current directory contents into the container at /app COPY . . @@ -49,7 +49,7 @@ USER root # Install runtime dependencies (libsndfile needed for audio processing on ARM64) RUN apk add --no-cache bash openssl tzdata nodejs npm python3 py3-pip libsndfile && \ - npm install -g npm@latest tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ + npm install -g npm@11.12.1 tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ # SECURITY FIX: npm bundles tar, glob, and brace-expansion at multiple nested # levels inside its dependency tree. `npm install -g ` only creates a # SEPARATE global package, it does NOT replace npm's internal copies. diff --git a/deploy/Dockerfile.ghcr_base b/deploy/Dockerfile.ghcr_base index 69b08a5893c..66e64e5b774 100644 --- a/deploy/Dockerfile.ghcr_base +++ b/deploy/Dockerfile.ghcr_base @@ -1,5 +1,5 @@ # Use the provided base image -FROM ghcr.io/berriai/litellm:main-latest +FROM ghcr.io/berriai/litellm:main-latest@sha256:7c311546c25e7bb6e8cafede9fcd3d0d622ac636b5c9418befaa32e85dfb0186 # Set the working directory to /app WORKDIR /app diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index ef2bb98db6e..1eed9d067f1 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -1,8 +1,8 @@ # Base image for building -ARG LITELLM_BUILD_IMAGE=python:3.11-alpine +ARG LITELLM_BUILD_IMAGE=python:3.11-alpine@sha256:f07e2ace46f560f09a6eeec7b4913b80ee99546e749ef82342a419a326620856 # Runtime image -ARG LITELLM_RUNTIME_IMAGE=python:3.11-alpine +ARG LITELLM_RUNTIME_IMAGE=python:3.11-alpine@sha256:f07e2ace46f560f09a6eeec7b4913b80ee99546e749ef82342a419a326620856 # Builder stage FROM $LITELLM_BUILD_IMAGE AS builder @@ -13,8 +13,8 @@ WORKDIR /app # Install build dependencies RUN apk add --no-cache gcc python3-dev musl-dev -RUN pip install --upgrade pip && \ - pip install build +RUN pip install --upgrade pip==26.0.1 && \ + pip install build==1.4.2 # Copy the current directory contents into the container at /app COPY . . diff --git a/docker/Dockerfile.custom_ui b/docker/Dockerfile.custom_ui index 9ab416944f5..f836190a49a 100644 --- a/docker/Dockerfile.custom_ui +++ b/docker/Dockerfile.custom_ui @@ -1,4 +1,5 @@ # Use the provided base image +# NOTE: This is a dev/branch-specific tag. Update digest when the base image is rebuilt. FROM ghcr.io/berriai/litellm:litellm_fwd_server_root_path-dev # Set the working directory to /app @@ -18,8 +19,8 @@ RUN apt-get update && apt-get upgrade -y \ libxslt1.1 \ libgnutls30 \ libc6 && \ - apt-get install -y nodejs npm && \ - npm install -g npm@latest tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ + apt-get install -y --no-install-recommends nodejs npm && \ + npm install -g npm@11.12.1 tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ GLOBAL="$(npm root -g)" && \ find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ diff --git a/docker/Dockerfile.database b/docker/Dockerfile.database index 3e1c55a75a8..0d3b225aac4 100644 --- a/docker/Dockerfile.database +++ b/docker/Dockerfile.database @@ -1,8 +1,8 @@ # Base image for building -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502 # Runtime image -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502 # Builder stage FROM $LITELLM_BUILD_IMAGE AS builder @@ -21,7 +21,7 @@ RUN apk add --no-cache \ openssl \ openssl-dev -RUN python -m pip install build +RUN python -m pip install build==1.4.2 # Copy the current directory contents into the container at /app COPY . . @@ -50,7 +50,7 @@ USER root # Install runtime dependencies RUN apk add --no-cache bash openssl tzdata nodejs npm python3 py3-pip libsndfile && \ - npm install -g npm@latest tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ + npm install -g npm@11.12.1 tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ GLOBAL="$(npm root -g)" && \ find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index e3e7ac0e0d6..8baef56bbd3 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -1,8 +1,8 @@ # Base image for building -ARG LITELLM_BUILD_IMAGE=python:3.11-slim +ARG LITELLM_BUILD_IMAGE=python:3.13-slim@sha256:739e7213785e88c0f702dcdc12c0973afcbd606dbf021a589cab77d6b00b579d # Runtime image -ARG LITELLM_RUNTIME_IMAGE=python:3.11-slim +ARG LITELLM_RUNTIME_IMAGE=python:3.13-slim@sha256:739e7213785e88c0f702dcdc12c0973afcbd606dbf021a589cab77d6b00b579d # Builder stage FROM $LITELLM_BUILD_IMAGE AS builder @@ -19,7 +19,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config \ && rm -rf /var/lib/apt/lists/* \ - && pip install --upgrade pip build + && pip install --upgrade pip==26.0.1 build==1.4.2 # Copy requirements first for better layer caching COPY requirements.txt . @@ -75,7 +75,7 @@ RUN apt-get update && apt-get upgrade -y \ nodejs \ npm \ && rm -rf /var/lib/apt/lists/* \ - && npm install -g npm@latest tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 \ + && npm install -g npm@11.12.1 tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 \ && GLOBAL="$(npm root -g)" \ && find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ diff --git a/docker/Dockerfile.health_check b/docker/Dockerfile.health_check index de62e4bd729..fb9cc201d2f 100644 --- a/docker/Dockerfile.health_check +++ b/docker/Dockerfile.health_check @@ -1,4 +1,4 @@ -FROM python:3.11-slim +FROM python:3.13-slim@sha256:739e7213785e88c0f702dcdc12c0973afcbd606dbf021a589cab77d6b00b579d WORKDIR /app @@ -12,5 +12,13 @@ RUN pip install --no-cache-dir -r requirements.txt # Make script executable RUN chmod +x /app/health_check_client.py +# Run as non-root user +RUN adduser --disabled-password --gecos "" --uid 1001 healthcheck +USER healthcheck + +# Health check +HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ + CMD python /app/health_check_client.py --help || exit 1 + # Set entrypoint ENTRYPOINT ["python", "/app/health_check_client.py"] diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index c224894779c..18c7d2fee67 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -1,6 +1,6 @@ # Base images -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502 +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:a5a619c1793039dcf92f02178f37c94bb3d6001403716da59d6092dfe8d9b502 ARG PROXY_EXTRAS_SOURCE=published # ----------------- @@ -27,7 +27,7 @@ RUN for i in 1 2 3; do \ nodejs \ npm && break || sleep 5; \ done \ - && pip install --no-cache-dir --upgrade pip build + && pip install --no-cache-dir --upgrade pip==26.0.1 build==1.4.2 # Cache Python dependencies COPY requirements.txt . @@ -41,13 +41,19 @@ COPY . . ENV LITELLM_NON_ROOT=true # Build Admin UI using the upstream command order while keeping a single RUN layer +# NOTE: --userconfig /dev/null bypasses .npmrc (which has ignore-scripts=true and +# min-release-age=3d) for this step only. This is safe because npm ci installs from +# package-lock.json with pinned versions + integrity hashes. RUN mkdir -p /var/lib/litellm/ui && \ - npm install -g npm@latest && npm cache clean --force && \ + mv /app/.npmrc /app/.npmrc.bak && \ + npm install -g npm@11.12.1 && npm cache clean --force && \ cd /app/ui/litellm-dashboard && \ if [ -f "/app/enterprise/enterprise_ui/enterprise_colors.json" ]; then \ cp /app/enterprise/enterprise_ui/enterprise_colors.json ./ui_colors.json; \ fi && \ + mv .npmrc .npmrc.bak && \ npm ci && \ + mv .npmrc.bak .npmrc && mv /app/.npmrc.bak /app/.npmrc && \ npm run build && \ cp -r /app/ui/litellm-dashboard/out/* /var/lib/litellm/ui/ && \ mkdir -p /var/lib/litellm/assets && \ @@ -106,7 +112,7 @@ RUN for i in 1 2 3; do \ apk add --no-cache python3 py3-pip bash openssl tzdata nodejs npm supervisor && break || sleep 5; \ done \ && apk upgrade --no-cache nodejs \ - && npm install -g npm@latest tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 \ + && npm install -g npm@11.12.1 tar@7.5.11 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 \ && GLOBAL="$(npm root -g)" \ && find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ diff --git a/docker/build_from_pip/Dockerfile.build_from_pip b/docker/build_from_pip/Dockerfile.build_from_pip index 05236008ded..6ac5f970670 100644 --- a/docker/build_from_pip/Dockerfile.build_from_pip +++ b/docker/build_from_pip/Dockerfile.build_from_pip @@ -1,4 +1,4 @@ -FROM python:3.13-alpine +FROM python:3.13-alpine@sha256:bb1f2fdb1065c85468775c9d680dcd344f6442a2d1181ef7916b60a623f11d40 WORKDIR /app @@ -13,7 +13,7 @@ RUN apk update && \ apk add --no-cache gcc musl-dev libffi-dev openssl openssl-dev rust cargo RUN python -m venv ${HOME}/venv -RUN ${HOME}/venv/bin/pip install --no-cache-dir --upgrade pip +RUN ${HOME}/venv/bin/pip install --no-cache-dir --upgrade pip==26.0.1 COPY docker/build_from_pip/requirements.txt . RUN --mount=type=cache,target=${HOME}/.cache/pip \ diff --git a/docker/build_from_pip/requirements.txt b/docker/build_from_pip/requirements.txt index cc14b99727f..ec6cf2438db 100644 --- a/docker/build_from_pip/requirements.txt +++ b/docker/build_from_pip/requirements.txt @@ -1,6 +1,6 @@ -litellm[proxy]==1.67.4.dev1 # Specify the litellm version you want to use -prometheus_client -langfuse -prisma -openai==1.99.9 +litellm[proxy]==1.83.0 +prometheus_client==0.20.0 +langfuse==2.59.7 +prisma==0.11.0 +openai==2.24.0 ddtrace==2.19.0 # for advanced DD tracing / profiling diff --git a/docker/install_auto_router.sh b/docker/install_auto_router.sh index 794f9a2bbce..057baa19f59 100755 --- a/docker/install_auto_router.sh +++ b/docker/install_auto_router.sh @@ -1,3 +1,3 @@ #!/bin/bash pip install semantic_router==0.1.11 --no-deps -pip install aurelio-sdk==0.0.19 \ No newline at end of file +pip install aurelio-sdk==0.0.19 --no-deps \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 8c95a4421bb..059c5e846f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,63 +20,60 @@ Documentation = "https://docs.litellm.ai" [tool.poetry.dependencies] python = ">=3.9,<4.0" -fastuuid = ">=0.13.0" -httpx = ">=0.23.0" -openai = ">=2.8.0" -python-dotenv = ">=0.2.0" -tiktoken = ">=0.7.0" -importlib-metadata = ">=6.8.0" -tokenizers = "*" -click = "*" -jinja2 = "^3.1.2" -aiohttp = ">=3.10" -pydantic = "^2.5.0" -jsonschema = ">=4.23.0,<5.0.0" -numpydoc = {version = "*", optional = true} # used in utils.py +fastuuid = "0.13.5" +httpx = "0.28.1" +openai = "2.24.0" +python-dotenv = "1.0.1" +tiktoken = "0.8.0" +importlib-metadata = "6.8.0" +tokenizers = "0.20.2" +click = "8.1.7" +jinja2 = "3.1.6" +aiohttp = "3.13.3" +pydantic = "2.12.5" +jsonschema = "4.26.0" +numpydoc = {version = "1.10.0", optional = true} # used in utils.py — not in Docker -uvicorn = {version = ">=0.32.1,<1.0.0", optional = true} -uvloop = {version = "^0.21.0", optional = true, markers="sys_platform != 'win32'"} -gunicorn = {version = "^23.0.0", optional = true} -fastapi = {version = ">=0.120.1", optional = true} -backoff = {version = "*", optional = true} -pyyaml = {version = "^6.0.1", optional = true} -rq = {version = "*", optional = true} -orjson = {version = "^3.9.7", optional = true} -apscheduler = {version = "^3.10.4", optional = true} -fastapi-sso = { version = "^0.16.0", optional = true } -PyJWT = { version = "^2.12.0", optional = true, python = ">=3.9" } -python-multipart = { version = ">=0.0.20", optional = true} -cryptography = {version = "*", optional = true} -prisma = {version = "^0.11.0", optional = true} -azure-identity = {version = "^1.15.0", optional = true, python = ">=3.9"} -azure-keyvault-secrets = {version = "^4.8.0", optional = true} -azure-storage-blob = {version="^12.25.1", optional=true} -google-cloud-kms = {version = "^2.21.3", optional = true} -google-cloud-iam = {version = "^2.19.1", optional = true} -google-cloud-aiplatform = {version = ">=1.38.0", optional = true} -resend = {version = ">=0.8.0", optional = true} -pynacl = {version = "^1.5.0", optional = true} -websockets = {version = "^15.0.1", optional = true} -boto3 = { version = "^1.40.76", optional = true } -redisvl = {version = "^0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"} -mcp = {version = ">=1.25.0,<2.0.0", optional = true, python = ">=3.10"} -a2a-sdk = {version = "^0.3.22", optional = true, python = ">=3.10"} -litellm-proxy-extras = {version = "^0.4.62", optional = true} -rich = {version = "^13.7.1", optional = true} +uvicorn = {version = "0.32.1", optional = true} # Docker uses 0.31.1 (requirements.txt); pyproject keeps main's minimum +uvloop = {version = "0.21.0", optional = true, markers="sys_platform != 'win32'"} +gunicorn = {version = "23.0.0", optional = true} +fastapi = {version = "0.120.1", optional = true} +backoff = {version = "2.2.1", optional = true} +pyyaml = {version = "6.0.2", optional = true} +rq = {version = "2.7.0", optional = true} # not in Docker +orjson = {version = "3.11.7", optional = true} +apscheduler = {version = "3.10.4", optional = true} +fastapi-sso = { version = "0.19.0", optional = true } +PyJWT = { version = "2.12.0", optional = true, python = ">=3.9" } +python-multipart = { version = "0.0.22", optional = true} +cryptography = {version = "46.0.5", optional = true} +prisma = {version = "0.11.0", optional = true} +azure-identity = {version = "1.16.1", optional = true, python = ">=3.9"} +azure-keyvault-secrets = {version = "4.10.0", optional = true} +azure-storage-blob = {version = "12.28.0", optional = true} +google-cloud-kms = {version = "2.24.2", optional = true} # not in Docker +google-cloud-iam = {version = "2.19.1", optional = true} +google-cloud-aiplatform = {version = "1.133.0", optional = true} +resend = {version = "2.23.0", optional = true} # not in Docker +pynacl = {version = "1.6.2", optional = true} +websockets = {version = "15.0.1", optional = true} +boto3 = { version = "1.40.76", optional = true } # Docker uses 1.40.53 (requirements.txt); pyproject keeps main's minimum +redisvl = {version = "0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"} +mcp = {version = "1.25.0", optional = true, python = ">=3.10"} +a2a-sdk = {version = "0.3.25", optional = true, python = ">=3.10"} +litellm-proxy-extras = {version = "0.4.62", optional = true} +rich = {version = "13.7.1", optional = true} litellm-enterprise = {version = "0.1.35", optional = true} -diskcache = {version = "^5.6.1", optional = true} -polars = {version = "^1.31.0", optional = true, python = ">=3.10"} -semantic-router = {version = ">=0.1.12", optional = true, python = ">=3.9,<3.14"} -mlflow = {version = ">3.1.4", optional = true, python = ">=3.10"} -soundfile = {version = "^0.12.1", optional = true} -pyroscope-io = {version = "^0.8", optional = true, markers = "sys_platform != 'win32'"} -# grpcio constraints: -# - 1.62.3+ required by grpcio-status -# - 1.68.0-1.68.1 has reconnect bug (https://github.com/grpc/grpc/issues/38290) -# - 1.75.0+ has Python 3.14 wheels and bug fix +diskcache = {version = "5.6.3", optional = true} # not in Docker +polars = {version = "1.31.0", optional = true, python = ">=3.10"} +semantic-router = {version = "0.1.12", optional = true, python = ">=3.9,<3.14"} # Docker uses 0.1.11 (install_auto_router.sh); pyproject keeps main's minimum +mlflow = {version = "3.9.0", optional = true, python = ">=3.10"} # not in Docker +soundfile = {version = "0.12.1", optional = true} +pyroscope-io = {version = "0.8.16", optional = true, markers = "sys_platform != 'win32'"} # not in Docker +# grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels) grpcio = [ - {version = ">=1.62.3,!=1.68.*,!=1.69.*,!=1.70.*,!=1.71.0,!=1.71.1,!=1.72.0,!=1.72.1,!=1.73.0", python = "<3.14", optional = true}, - {version = ">=1.75.0", python = ">=3.14", optional = true}, + {version = "1.80.0", python = "<3.14", optional = true}, + {version = "1.80.0", python = ">=3.14", optional = true}, ] [tool.poetry.extras] @@ -143,41 +140,41 @@ litellm = 'litellm:run_server' litellm-proxy = 'litellm.proxy.client.cli:cli' [tool.poetry.group.dev.dependencies] -diff-cover = "^9.0" -flake8 = "^6.1.0" -black = "^23.12.0" -mypy = "^1.0" -pytest = "^7.4.3" -pytest-mock = "^3.12.0" -pytest-asyncio = "^0.21.1" -pytest-postgresql = "^6.0.0" -pytest-xdist = "^3.5.0" -requests-mock = "^1.12.1" -responses = "^0.25.7" -respx = "^0.22.0" -ruff = "^0.2.1" -types-requests = "*" -types-setuptools = "*" -types-redis = "*" -types-PyYAML = "*" -opentelemetry-api = "^1.28.0" -opentelemetry-sdk = "^1.28.0" -opentelemetry-exporter-otlp = "^1.28.0" -langfuse = "^2.45.0" -fastapi-offline = "^1.7.3" -fakeredis = "^2.27.1" -pytest-rerunfailures = "^14.0" -parameterized = "^0.9.0" +diff-cover = "10.2.0" +flake8 = "7.3.0" +black = "26.1.0" +mypy = "1.19.0" +pytest = "9.0.2" +pytest-mock = "3.15.1" +pytest-asyncio = "1.3.0" +pytest-postgresql = "8.0.0" +pytest-xdist = "3.8.0" +requests-mock = "1.12.1" +responses = "0.26.0" +respx = "0.22.0" +ruff = "0.15.3" +types-requests = "2.32.4.20260107" +types-setuptools = "82.0.0.20260210" +types-redis = "4.6.0.20241004" +types-PyYAML = "6.0.12.20250915" +opentelemetry-api = "1.28.0" +opentelemetry-sdk = "1.28.0" +opentelemetry-exporter-otlp = "1.28.0" +langfuse = "2.59.7" +fastapi-offline = "1.7.6" +fakeredis = "2.34.1" +pytest-rerunfailures = "16.1" +parameterized = "0.9.0" [tool.poetry.group.proxy-dev.dependencies] prisma = "0.11.0" -hypercorn = "^0.15.0" +hypercorn = "0.18.0" prometheus-client = "0.20.0" -opentelemetry-api = "^1.28.0" -opentelemetry-sdk = "^1.28.0" -opentelemetry-exporter-otlp = "^1.28.0" -azure-identity = {version = "^1.15.0", python = ">=3.9"} -a2a-sdk = {version = "^0.3.22", python = ">=3.10"} +opentelemetry-api = "1.28.0" +opentelemetry-sdk = "1.28.0" +opentelemetry-exporter-otlp = "1.28.0" +azure-identity = {version = "1.16.1", python = ">=3.9"} +a2a-sdk = {version = "0.3.25", python = ">=3.10"} [build-system] requires = ["poetry-core", "wheel"] diff --git a/requirements.txt b/requirements.txt index 1cccdf8ccc8..27112f031fb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ # LITELLM PROXY DEPENDENCIES # # Security: explicit pins for transitive deps (CVE fixes) -urllib3>=2.6.0 # CVE-2025-66471, CVE-2025-66418, CVE-2026-21441 -tornado>=6.5.5 # CVE-2025-67725, CVE-2025-67726, CVE-2025-67724, CVE-2026-31958, GHSA-78cv-mqj4-43f7 -filelock>=3.20.1 # CVE-2025-68146 -h11>=0.16.0 # CVE-2025-43859, GHSA-vqfr-h8mv-ghfj — HTTP request smuggling -wheel>=0.46.2 # CVE-2026-24049 — path traversal +urllib3==2.6.3 # CVE-2025-66471, CVE-2025-66418, CVE-2026-21441 +tornado==6.5.5 # CVE-2025-67725, CVE-2025-67726, CVE-2025-67724, CVE-2026-31958, GHSA-78cv-mqj4-43f7 +filelock==3.25.2 # CVE-2025-68146 +h11==0.16.0 # CVE-2025-43859, GHSA-vqfr-h8mv-ghfj — HTTP request smuggling +wheel==0.46.3 # CVE-2026-24049 — path traversal Pillow==12.1.1 #GHSA-cfh3-3jmp-rvhc cryptography==46.0.5 #GHSA-r6ph-v2qm-q3c2 @@ -41,8 +41,8 @@ polars==1.31.0 # for data processing apscheduler==3.10.4 # for resetting budget in background fastapi-sso==0.19.0 # admin UI, SSO pyjwt[crypto]==2.12.0 ; python_version >= "3.9" -python-multipart>=0.0.20 # admin UI -jaraco.context>=6.1.0 +python-multipart==0.0.22 # admin UI +jaraco.context==6.1.2 azure-ai-contentsafety==1.0.0 # for azure content safety azure-identity==1.16.1 ; python_version >= "3.9" # for azure content safety azure-keyvault==4.2.0 # for azure KMS integration @@ -50,10 +50,10 @@ azure-storage-file-datalake==12.20.0 # for azure buck storage logging opentelemetry-api==1.28.0 opentelemetry-sdk==1.28.0 opentelemetry-exporter-otlp==1.28.0 -a2a-sdk>=0.3.22 ; python_version >= "3.10" -# grpcio: 1.68.0-1.68.1 has reconnect bug (#38290), 1.75+ has Python 3.14 wheels + fix -grpcio>=1.62.3,!=1.68.*,!=1.69.*,!=1.70.*,!=1.71.0,!=1.71.1,!=1.72.0,!=1.72.1,!=1.73.0; python_version < "3.14" -grpcio>=1.75.0; python_version >= "3.14" +a2a-sdk==0.3.25 ; python_version >= "3.10" +# grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels) +grpcio==1.80.0; python_version < "3.14" +grpcio==1.80.0; python_version >= "3.14" sentry_sdk==2.21.0 # for sentry error handling detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests tzdata==2025.1 # IANA time zone database @@ -67,15 +67,22 @@ tokenizers==0.20.2 # for calculating usage click==8.1.7 # for proxy cli rich==13.7.1 # for litellm proxy cli jinja2==3.1.6 # for prompt templates -aioboto3==15.5.0 # for async sagemaker calls (updated to match boto3 1.40.73) +aioboto3==15.5.0 # for async sagemaker calls aiohttp==3.13.3 # for network calls tenacity==8.5.0 # for retrying requests, when litellm.num_retries set -pydantic>=2.11,<3 # proxy + openai req. + mcp -jsonschema>=4.23.0,<5.0.0 # validating json schema - aligned with openapi-core + mcp +pydantic==2.12.5 # proxy + openai req. + mcp +jsonschema==4.26.0 # validating json schema - aligned with openapi-core + mcp websockets==15.0.1 # for realtime API soundfile==0.12.1 # for audio file processing openapi-core==0.21.0 # for OpenAPI compliance tests -pypdf>=6.7.3 # for PDF text extraction in RAG ingestion (CVE-2026-27888) +pypdf==6.9.2 # for PDF text extraction in RAG ingestion (CVE-2026-27888) + +# Transitive deps pinned to prevent floating between builds +aiofiles==24.1.0 # transitive dep (langfuse) +colorlog==6.10.1 # transitive dep (ddtrace) +grpc-google-iam-v1==0.14.3 # transitive dep (google-cloud-iam) +hf-xet==1.4.2 # transitive dep (huggingface_hub) +requests-toolbelt==1.0.0 # transitive dep (langfuse) ######################## # LITELLM ENTERPRISE DEPENDENCIES diff --git a/scripts/health_check/health_check_requirements.txt b/scripts/health_check/health_check_requirements.txt index c9d2650c884..4aba4d49edb 100644 --- a/scripts/health_check/health_check_requirements.txt +++ b/scripts/health_check/health_check_requirements.txt @@ -1,2 +1,2 @@ -httpx>=0.24.0 -pyyaml>=6.0 +httpx==0.28.1 +pyyaml==6.0.2 From 296dd3e8a2b66f5ce645fca63ae338d50e656f78 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 00:25:38 -0700 Subject: [PATCH 02/32] [Infra] Fix pyproject.toml pins for Poetry Python 3.9 compatibility Pin pyproject.toml deps from PyPI resolution of `pip install litellm[proxy]==1.83.0` instead of Docker freeze versions. Docker builds (requirements.txt) and PyPI installs (pyproject.toml) are independent dependency paths. Some packages pinned to 3.9-compatible versions where latest requires >=3.10. Co-Authored-By: Claude Opus 4.6 (1M context) --- poetry.lock | 1665 ++++++++++++++++++++++++++---------------------- pyproject.toml | 82 +-- 2 files changed, 932 insertions(+), 815 deletions(-) diff --git a/poetry.lock b/poetry.lock index e369d1be75f..1fadf184772 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,15 +2,15 @@ [[package]] name = "a2a-sdk" -version = "0.3.22" +version = "0.3.25" description = "A2A Python SDK" optional = false python-versions = ">=3.10" groups = ["main", "proxy-dev"] markers = "python_version >= \"3.10\"" files = [ - {file = "a2a_sdk-0.3.22-py3-none-any.whl", hash = "sha256:b98701135bb90b0ff85d35f31533b6b7a299bf810658c1c65f3814a6c15ea385"}, - {file = "a2a_sdk-0.3.22.tar.gz", hash = "sha256:77a5694bfc4f26679c11b70c7f1062522206d430b34bc1215cfbb1eba67b7e7d"}, + {file = "a2a_sdk-0.3.25-py3-none-any.whl", hash = "sha256:2fce38faea82eb0b6f9f9c2bcf761b0d78612c80ef0e599b50d566db1b2654b5"}, + {file = "a2a_sdk-0.3.25.tar.gz", hash = "sha256:afda85bab8d6af0c5d15e82f326c94190f6be8a901ce562d045a338b7127242f"}, ] [package.dependencies] @@ -21,7 +21,7 @@ protobuf = ">=5.29.5" pydantic = ">=2.11.3" [package.extras] -all = ["cryptography (>=43.0.0)", "fastapi (>=0.115.2)", "grpcio (>=1.60)", "grpcio-reflection (>=1.7.0)", "grpcio-tools (>=1.60)", "opentelemetry-api (>=1.33.0)", "opentelemetry-sdk (>=1.33.0)", "pyjwt (>=2.0.0)", "sqlalchemy[aiomysql,asyncio] (>=2.0.0)", "sqlalchemy[aiosqlite,asyncio] (>=2.0.0)", "sqlalchemy[asyncio,postgresql-asyncpg] (>=2.0.0)", "sse-starlette", "starlette"] +all = ["cryptography (>=43.0.0)", "fastapi (>=0.115.2)", "google-cloud-aiplatform (>=1.140.0)", "grpcio (>=1.60)", "grpcio-reflection (>=1.7.0)", "grpcio-tools (>=1.60)", "opentelemetry-api (>=1.33.0)", "opentelemetry-sdk (>=1.33.0)", "pyjwt (>=2.0.0)", "sqlalchemy[aiomysql,asyncio] (>=2.0.0)", "sqlalchemy[aiosqlite,asyncio] (>=2.0.0)", "sqlalchemy[asyncio,postgresql-asyncpg] (>=2.0.0)", "sse-starlette", "starlette"] encryption = ["cryptography (>=43.0.0)"] grpc = ["grpcio (>=1.60)", "grpcio-reflection (>=1.7.0)", "grpcio-tools (>=1.60)"] http-server = ["fastapi (>=0.115.2)", "sse-starlette", "starlette"] @@ -31,6 +31,7 @@ signing = ["pyjwt (>=2.0.0)"] sql = ["sqlalchemy[aiomysql,asyncio] (>=2.0.0)", "sqlalchemy[aiosqlite,asyncio] (>=2.0.0)", "sqlalchemy[asyncio,postgresql-asyncpg] (>=2.0.0)"] sqlite = ["sqlalchemy[aiosqlite,asyncio] (>=2.0.0)"] telemetry = ["opentelemetry-api (>=1.33.0)", "opentelemetry-sdk (>=1.33.0)"] +vertex = ["google-cloud-aiplatform (>=1.140.0)"] [[package]] name = "aiofiles" @@ -59,132 +60,132 @@ files = [ [[package]] name = "aiohttp" -version = "3.13.2" +version = "3.13.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155"}, - {file = "aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c"}, - {file = "aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636"}, - {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da"}, - {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725"}, - {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5"}, - {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3"}, - {file = "aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802"}, - {file = "aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a"}, - {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204"}, - {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22"}, - {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d"}, - {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f"}, - {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f"}, - {file = "aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6"}, - {file = "aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251"}, - {file = "aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514"}, - {file = "aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0"}, - {file = "aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb"}, - {file = "aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9"}, - {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613"}, - {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead"}, - {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780"}, - {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a"}, - {file = "aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592"}, - {file = "aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab"}, - {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30"}, - {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40"}, - {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948"}, - {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf"}, - {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782"}, - {file = "aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8"}, - {file = "aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec"}, - {file = "aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c"}, - {file = "aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b"}, - {file = "aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc"}, - {file = "aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7"}, - {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb"}, - {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3"}, - {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f"}, - {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6"}, - {file = "aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e"}, - {file = "aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7"}, - {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d"}, - {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b"}, - {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8"}, - {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16"}, - {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169"}, - {file = "aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248"}, - {file = "aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e"}, - {file = "aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45"}, - {file = "aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be"}, - {file = "aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742"}, - {file = "aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293"}, - {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811"}, - {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a"}, - {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4"}, - {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a"}, - {file = "aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e"}, - {file = "aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb"}, - {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded"}, - {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b"}, - {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8"}, - {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04"}, - {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476"}, - {file = "aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23"}, - {file = "aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254"}, - {file = "aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a"}, - {file = "aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b"}, - {file = "aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61"}, - {file = "aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4"}, - {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b"}, - {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694"}, - {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906"}, - {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9"}, - {file = "aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011"}, - {file = "aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6"}, - {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213"}, - {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49"}, - {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae"}, - {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa"}, - {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4"}, - {file = "aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a"}, - {file = "aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940"}, - {file = "aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4"}, - {file = "aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673"}, - {file = "aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd"}, - {file = "aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3"}, - {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf"}, - {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e"}, - {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5"}, - {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad"}, - {file = "aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e"}, - {file = "aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61"}, - {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661"}, - {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98"}, - {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693"}, - {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a"}, - {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be"}, - {file = "aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c"}, - {file = "aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734"}, - {file = "aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f"}, - {file = "aiohttp-3.13.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7fbdf5ad6084f1940ce88933de34b62358d0f4a0b6ec097362dcd3e5a65a4989"}, - {file = "aiohttp-3.13.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7c3a50345635a02db61792c85bb86daffac05330f6473d524f1a4e3ef9d0046d"}, - {file = "aiohttp-3.13.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0e87dff73f46e969af38ab3f7cb75316a7c944e2e574ff7c933bc01b10def7f5"}, - {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2adebd4577724dcae085665f294cc57c8701ddd4d26140504db622b8d566d7aa"}, - {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e036a3a645fe92309ec34b918394bb377950cbb43039a97edae6c08db64b23e2"}, - {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:23ad365e30108c422d0b4428cf271156dd56790f6dd50d770b8e360e6c5ab2e6"}, - {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1f9b2c2d4b9d958b1f9ae0c984ec1dd6b6689e15c75045be8ccb4011426268ca"}, - {file = "aiohttp-3.13.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a92cf4b9bea33e15ecbaa5c59921be0f23222608143d025c989924f7e3e0c07"}, - {file = "aiohttp-3.13.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:070599407f4954021509193404c4ac53153525a19531051661440644728ba9a7"}, - {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:29562998ec66f988d49fb83c9b01694fa927186b781463f376c5845c121e4e0b"}, - {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4dd3db9d0f4ebca1d887d76f7cdbcd1116ac0d05a9221b9dad82c64a62578c4d"}, - {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d7bc4b7f9c4921eba72677cd9fedd2308f4a4ca3e12fab58935295ad9ea98700"}, - {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:dacd50501cd017f8cccb328da0c90823511d70d24a323196826d923aad865901"}, - {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:8b2f1414f6a1e0683f212ec80e813f4abef94c739fd090b66c9adf9d2a05feac"}, - {file = "aiohttp-3.13.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04c3971421576ed24c191f610052bcb2f059e395bc2489dd99e397f9bc466329"}, - {file = "aiohttp-3.13.2-cp39-cp39-win32.whl", hash = "sha256:9f377d0a924e5cc94dc620bc6366fc3e889586a7f18b748901cf016c916e2084"}, - {file = "aiohttp-3.13.2-cp39-cp39-win_amd64.whl", hash = "sha256:9c705601e16c03466cb72011bd1af55d68fa65b045356d8f96c216e5f6db0fa5"}, - {file = "aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7"}, + {file = "aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9"}, + {file = "aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3"}, + {file = "aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06"}, + {file = "aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14"}, + {file = "aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3"}, + {file = "aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c"}, + {file = "aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc"}, + {file = "aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b"}, + {file = "aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3"}, + {file = "aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b"}, + {file = "aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83"}, + {file = "aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67"}, + {file = "aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1"}, ] [package.dependencies] @@ -198,7 +199,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +speedups = ["Brotli (>=1.2) ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi (>=1.2) ; platform_python_implementation != \"CPython\""] [[package]] name = "aiosignal" @@ -299,15 +300,15 @@ trio = ["trio (>=0.31.0)"] [[package]] name = "apscheduler" -version = "3.11.1" +version = "3.11.2" description = "In-process task scheduler with Cron-like capabilities" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "apscheduler-3.11.1-py3-none-any.whl", hash = "sha256:6162cb5683cb09923654fa9bdd3130c4be4bfda6ad8990971c9597ecd52965d2"}, - {file = "apscheduler-3.11.1.tar.gz", hash = "sha256:0db77af6400c84d1747fe98a04b8b58f0080c77d11d338c4f507a9752880f221"}, + {file = "apscheduler-3.11.2-py3-none-any.whl", hash = "sha256:ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d"}, + {file = "apscheduler-3.11.2.tar.gz", hash = "sha256:2a9966b052ec805f020c8c4c3ae6e6a06e24b1bf19f2e11d91d8cca0473eef41"}, ] [package.dependencies] @@ -321,7 +322,7 @@ mongodb = ["pymongo (>=3.0)"] redis = ["redis (>=3.0)"] rethinkdb = ["rethinkdb (>=2.4.0)"] sqlalchemy = ["sqlalchemy (>=1.4)"] -test = ["APScheduler[etcd,mongodb,redis,rethinkdb,sqlalchemy,tornado,zookeeper]", "PySide6 ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "anyio (>=4.5.2)", "gevent ; python_version < \"3.14\"", "pytest", "pytz", "twisted ; python_version < \"3.14\""] +test = ["APScheduler[etcd,mongodb,redis,rethinkdb,sqlalchemy,tornado,zookeeper]", "PySide6 ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "anyio (>=4.5.2)", "gevent ; python_version < \"3.14\"", "pytest", "pytest-timeout", "pytz", "twisted ; python_version < \"3.14\""] tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] @@ -396,20 +397,20 @@ tracing = ["opentelemetry-api (>=1.26,<2.0)"] [[package]] name = "azure-identity" -version = "1.25.1" +version = "1.25.3" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.9" groups = ["main", "proxy-dev"] files = [ - {file = "azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651"}, - {file = "azure_identity-1.25.1.tar.gz", hash = "sha256:87ca8328883de6036443e1c37b40e8dc8fb74898240f61071e09d2e369361456"}, + {file = "azure_identity-1.25.3-py3-none-any.whl", hash = "sha256:f4d0b956a8146f30333e071374171f3cfa7bdb8073adb8c3814b65567aa7447c"}, + {file = "azure_identity-1.25.3.tar.gz", hash = "sha256:ab23c0d63015f50b630ef6c6cf395e7262f439ce06e5d07a64e874c724f8d9e6"}, ] [package.dependencies] azure-core = ">=1.31.0" cryptography = ">=2.5" -msal = ">=1.30.0" +msal = ">=1.35.1" msal-extensions = ">=1.2.0" typing-extensions = ">=4.0.0" @@ -433,15 +434,15 @@ typing-extensions = ">=4.6.0" [[package]] name = "azure-storage-blob" -version = "12.27.1" +version = "12.28.0" description = "Microsoft Azure Blob Storage Client Library for Python" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "azure_storage_blob-12.27.1-py3-none-any.whl", hash = "sha256:65d1e25a4628b7b6acd20ff7902d8da5b4fde8e46e19c8f6d213a3abc3ece272"}, - {file = "azure_storage_blob-12.27.1.tar.gz", hash = "sha256:a1596cc4daf5dac9be115fcb5db67245eae894cf40e4248243754261f7b674a6"}, + {file = "azure_storage_blob-12.28.0-py3-none-any.whl", hash = "sha256:00fb1db28bf6a7b7ecaa48e3b1d5c83bfadacc5a678b77826081304bd87d6461"}, + {file = "azure_storage_blob-12.28.0.tar.gz", hash = "sha256:e7d98ea108258d29aa0efbfd591b2e2075fa1722a2fae8699f0b3c9de11eff41"}, ] [package.dependencies] @@ -482,36 +483,49 @@ files = [ ] markers = {main = "extra == \"proxy\""} +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +description = "Backport of asyncio.Runner, a context manager that controls event loop life cycle." +optional = false +python-versions = "<3.11,>=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, + {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, +] + [[package]] name = "black" -version = "23.12.1" +version = "24.10.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [package.dependencies] @@ -525,7 +539,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4) ; sys_platform != \"win32\" or implementation_name != \"pypy\"", "aiohttp (>=3.7.4,!=3.9.0) ; sys_platform == \"win32\" and implementation_name == \"pypy\""] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -544,36 +558,36 @@ files = [ [[package]] name = "boto3" -version = "1.40.76" +version = "1.42.80" description = "The AWS SDK for Python" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "boto3-1.40.76-py3-none-any.whl", hash = "sha256:8df6df755727be40ad9e309cfda07f9a12c147e17b639430c55d4e4feee8a167"}, - {file = "boto3-1.40.76.tar.gz", hash = "sha256:16f4cf97f8dd8e0aae015f4dc66219bd7716a91a40d1e2daa0dafa241a4761c5"}, + {file = "boto3-1.42.80-py3-none-any.whl", hash = "sha256:293cbdeaec7eda2a0b08e6a9c2bf1a51c54453863137d45a6431058a9280fdda"}, + {file = "boto3-1.42.80.tar.gz", hash = "sha256:797cec65f8a36dde38d2397119a114ab0d807cf92c43fb44b72b0522558acc0a"}, ] [package.dependencies] -botocore = ">=1.40.76,<1.41.0" +botocore = ">=1.42.80,<1.43.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.14.0,<0.15.0" +s3transfer = ">=0.16.0,<0.17.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.76" +version = "1.42.80" description = "Low-level, data-driven core of boto 3." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "botocore-1.40.76-py3-none-any.whl", hash = "sha256:fe425d386e48ac64c81cbb4a7181688d813df2e2b4c78b95ebe833c9e868c6f4"}, - {file = "botocore-1.40.76.tar.gz", hash = "sha256:2b16024d68b29b973005adfb5039adfe9099ebe772d40a90ca89f2e165c495dc"}, + {file = "botocore-1.42.80-py3-none-any.whl", hash = "sha256:7291632b2ede71b7c69e6e366480bb6e2a5d2fae8f7d2d2eb49215e32b7c7a12"}, + {file = "botocore-1.42.80.tar.gz", hash = "sha256:fe32af53dc87f5f4d61879bc231e2ca2cc0719b19b8f6d268e82a34f713a8a09"}, ] [package.dependencies] @@ -585,20 +599,20 @@ urllib3 = [ ] [package.extras] -crt = ["awscrt (==0.28.4)"] +crt = ["awscrt (==0.31.2)"] [[package]] name = "cachetools" version = "6.2.2" description = "Extensible memoizing collections and decorators" -optional = false +optional = true python-versions = ">=3.9" -groups = ["main", "proxy-dev"] +groups = ["main"] +markers = "python_version >= \"3.10\" and extra == \"mlflow\"" files = [ {file = "cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace"}, {file = "cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6"}, ] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} [[package]] name = "certifi" @@ -1109,6 +1123,25 @@ dev = ["autoflake", "black", "build", "databricks-connect", "httpx", "ipython", notebook = ["ipython (>=8,<10)", "ipywidgets (>=8,<9)"] openai = ["httpx", "langchain-openai ; python_version > \"3.7\"", "openai"] +[[package]] +name = "deprecated" +version = "1.3.1" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main", "dev", "proxy-dev"] +files = [ + {file = "deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f"}, + {file = "deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223"}, +] +markers = {main = "python_version >= \"3.10\""} + +[package.dependencies] +wrapt = ">=1.10,<3" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] + [[package]] name = "diff-cover" version = "9.7.2" @@ -1285,20 +1318,20 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "fakeredis" -version = "2.33.0" +version = "2.34.1" description = "Python implementation of redis API, can be used for testing purposes." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "fakeredis-2.33.0-py3-none-any.whl", hash = "sha256:de535f3f9ccde1c56672ab2fdd6a8efbc4f2619fc2f1acc87b8737177d71c965"}, - {file = "fakeredis-2.33.0.tar.gz", hash = "sha256:d7bc9a69d21df108a6451bbffee23b3eba432c21a654afc7ff2d295428ec5770"}, + {file = "fakeredis-2.34.1-py3-none-any.whl", hash = "sha256:0107ec99d48913e7eec2a5e3e2403d1bd5f8aa6489d1a634571b975289c48f12"}, + {file = "fakeredis-2.34.1.tar.gz", hash = "sha256:4ff55606982972eecce3ab410e03d746c11fe5deda6381d913641fbd8865ea9b"}, ] [package.dependencies] redis = [ {version = ">=4.3", markers = "python_version > \"3.8\""}, - {version = ">=4.3,<7.1.0", markers = "python_version < \"3.10\" and python_version > \"3.8\""}, + {version = ">=4.3,<7.2", markers = "python_version < \"3.10\" and python_version > \"3.8\""}, ] sortedcontainers = ">=2" typing-extensions = {version = ">=4.7,<5.0", markers = "python_version < \"3.11\""} @@ -1313,14 +1346,14 @@ valkey = ["valkey (>=6) ; python_version >= \"3.8\""] [[package]] name = "fastapi" -version = "0.121.3" +version = "0.124.4" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "fastapi-0.121.3-py3-none-any.whl", hash = "sha256:0c78fc87587fcd910ca1bbf5bc8ba37b80e119b388a7206b39f0ecc95ebf53e9"}, - {file = "fastapi-0.121.3.tar.gz", hash = "sha256:0055bc24fe53e56a40e9e0ad1ae2baa81622c406e548e501e717634e2dfbc40b"}, + {file = "fastapi-0.124.4-py3-none-any.whl", hash = "sha256:6d1e703698443ccb89e50abe4893f3c84d9d6689c0cf1ca4fad6d3c15cf69f15"}, + {file = "fastapi-0.124.4.tar.gz", hash = "sha256:0e9422e8d6b797515f33f500309f6e1c98ee4e85563ba0f2debb282df6343763"}, ] markers = {main = "python_version >= \"3.10\" and (extra == \"mlflow\" or extra == \"proxy\") or extra == \"proxy\""} @@ -1337,14 +1370,14 @@ standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[stand [[package]] name = "fastapi-offline" -version = "1.7.5" +version = "1.7.6" description = "FastAPI without reliance on CDNs for docs" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "fastapi_offline-1.7.5-py3-none-any.whl", hash = "sha256:00369632d604e8156b9ca9ab9c65e58ad8beff83d1ffc7bdbcec4a86173d51b4"}, - {file = "fastapi_offline-1.7.5.tar.gz", hash = "sha256:07a58cb8d8fab68ba625698414b4cac833bb2d94d82dc0fbc2a8519bee7af87d"}, + {file = "fastapi_offline-1.7.6-py3-none-any.whl", hash = "sha256:24d6851b5a94c50f669594b7ab9d1bbe3a4c0a53c4f4e9ce47798ff4591790d2"}, + {file = "fastapi_offline-1.7.6.tar.gz", hash = "sha256:c84d08584faa646932951b493106992caa79b838e454f14dd410cef9a1a5e07d"}, ] [package.dependencies] @@ -1475,20 +1508,20 @@ files = [ [[package]] name = "flake8" -version = "6.1.0" +version = "7.3.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false -python-versions = ">=3.8.1" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, + {file = "flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e"}, + {file = "flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" +pycodestyle = ">=2.14.0,<2.15.0" +pyflakes = ">=3.4.0,<3.5.0" [[package]] name = "flask" @@ -1897,49 +1930,50 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] [[package]] name = "google-auth" -version = "2.43.0" +version = "2.49.1" description = "Google Authentication Library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main", "proxy-dev"] files = [ - {file = "google_auth-2.43.0-py2.py3-none-any.whl", hash = "sha256:af628ba6fa493f75c7e9dbe9373d148ca9f4399b5ea29976519e0a3848eddd16"}, - {file = "google_auth-2.43.0.tar.gz", hash = "sha256:88228eee5fc21b62a1b5fe773ca15e67778cb07dc8363adcb4a8827b52d81483"}, + {file = "google_auth-2.49.1-py3-none-any.whl", hash = "sha256:195ebe3dca18eddd1b3db5edc5189b76c13e96f29e73043b923ebcf3f1a860f7"}, + {file = "google_auth-2.49.1.tar.gz", hash = "sha256:16d40da1c3c5a0533f57d268fe72e0ebb0ae1cc3b567024122651c045d879b64"}, ] markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] -cachetools = ">=2.0.0,<7.0" +cryptography = ">=38.0.3" pyasn1-modules = ">=0.2.1" -rsa = ">=3.1.4,<5" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] -enterprise-cert = ["cryptography", "pyopenssl"] -pyjwt = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyjwt (>=2.0)"] -pyopenssl = ["cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +cryptography = ["cryptography (>=38.0.3)"] +enterprise-cert = ["pyopenssl"] +pyjwt = ["pyjwt (>=2.0)"] +pyopenssl = ["pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0)"] -testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +rsa = ["rsa (>=3.1.4,<5)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "flask", "freezegun", "grpcio", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] urllib3 = ["packaging", "urllib3"] [[package]] name = "google-cloud-aiplatform" -version = "1.130.0" +version = "1.133.0" description = "Vertex AI API client library" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"google\"" files = [ - {file = "google_cloud_aiplatform-1.130.0-py2.py3-none-any.whl", hash = "sha256:f578ccee55655dd9e2300cfcafb178e47c3dfdcf746ad465234b875d3e955929"}, - {file = "google_cloud_aiplatform-1.130.0.tar.gz", hash = "sha256:f66aeb23f0a6848fc2d5bbdf1b5777c3cf8e06056f73ef815317abf89d5a0262"}, + {file = "google_cloud_aiplatform-1.133.0-py2.py3-none-any.whl", hash = "sha256:dfc81228e987ca10d1c32c7204e2131b3c8d6b7c8e0b4e23bf7c56816bc4c566"}, + {file = "google_cloud_aiplatform-1.133.0.tar.gz", hash = "sha256:3a6540711956dd178daaab3c2c05db476e46d94ac25912b8cf4f59b00b058ae0"}, ] [package.dependencies] docstring_parser = "<1" google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.8.dev0,<3.0.0", extras = ["grpc"]} -google-auth = ">=2.14.1,<3.0.0" +google-auth = ">=2.47.0,<3.0.0" google-cloud-bigquery = ">=1.15.0,<3.20.0 || >3.20.0,<4.0.0" google-cloud-resource-manager = ">=1.3.3,<3.0.0" google-cloud-storage = [ @@ -1951,7 +1985,6 @@ packaging = ">=14.3" proto-plus = ">=1.22.3,<2.0.0" protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" pydantic = "<3" -shapely = "<3.0.0" typing_extensions = "*" [package.extras] @@ -1964,21 +1997,21 @@ cloud-profiler = ["tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "werkzeug (>=2 datasets = ["pyarrow (>=10.0.1) ; python_version == \"3.11\"", "pyarrow (>=14.0.0) ; python_version >= \"3.12\"", "pyarrow (>=3.0.0,<8.0.0) ; python_version < \"3.11\""] endpoint = ["requests (>=2.28.1)", "requests-toolbelt (<=1.0.0)"] evaluation = ["jsonschema", "litellm (>=1.72.4,!=1.77.2,!=1.77.3,!=1.77.4)", "pandas (>=1.0.0)", "pyyaml", "ruamel.yaml", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "tqdm (>=4.23.0)"] -full = ["docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0) ; python_version < \"3.13\"", "fastapi (>=0.71.0,<=0.114.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "httpx (>=0.23.0,<=0.28.1)", "immutabledict", "jsonschema", "lit-nlp (==0.4.0) ; python_version < \"3.14\"", "litellm (>=1.72.4,!=1.77.2,!=1.77.3,!=1.77.4)", "mlflow (>=1.27.0) ; python_version >= \"3.13\"", "mlflow (>=1.27.0,<=2.16.0) ; python_version < \"3.13\"", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pyarrow (>=10.0.1) ; python_version == \"3.11\"", "pyarrow (>=14.0.0) ; python_version >= \"3.12\"", "pyarrow (>=3.0.0,<8.0.0) ; python_version < \"3.11\"", "pyarrow (>=6.0.1)", "pyyaml", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || ==2.33.* || >=2.42.dev0,<=2.42.0) ; python_version < \"3.11\"", "ray[default] (>=2.5,<=2.47.1) ; python_version == \"3.11\"", "requests (>=2.28.1)", "requests-toolbelt (<=1.0.0)", "ruamel.yaml", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<4.0.0)"] +full = ["docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0) ; python_version < \"3.13\"", "fastapi (>=0.71.0,<=0.124.4)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "httpx (>=0.23.0,<=0.28.1)", "immutabledict", "jsonschema", "lit-nlp (==0.4.0) ; python_version < \"3.13\"", "litellm (>=1.72.4,!=1.77.2,!=1.77.3,!=1.77.4)", "mlflow (>=1.27.0) ; python_version >= \"3.13\"", "mlflow (>=1.27.0,<=2.16.0) ; python_version < \"3.13\"", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pyarrow (>=10.0.1) ; python_version == \"3.11\"", "pyarrow (>=14.0.0) ; python_version >= \"3.12\"", "pyarrow (>=3.0.0,<8.0.0) ; python_version < \"3.11\"", "pyarrow (>=6.0.1)", "pyyaml", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || ==2.33.* || >=2.42.dev0,<=2.42.0) ; python_version < \"3.11\"", "ray[default] (>=2.5,<=2.47.1) ; python_version == \"3.11\"", "requests (>=2.28.1)", "requests-toolbelt (<=1.0.0)", "ruamel.yaml", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<4.0.0)"] langchain = ["langchain (>=0.3,<0.4)", "langchain-core (>=0.3,<0.4)", "langchain-google-vertexai (>=2.0.22,<3)", "langgraph (>=0.2.45,<0.4)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)"] langchain-testing = ["absl-py", "cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "langchain (>=0.3,<0.4)", "langchain-core (>=0.3,<0.4)", "langchain-google-vertexai (>=2.0.22,<3)", "langgraph (>=0.2.45,<0.4)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)", "opentelemetry-exporter-gcp-logging (>=1.11.0a0,<2.0.0)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-exporter-otlp-proto-http (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.11.1,<3)", "pytest-xdist", "typing_extensions"] -lit = ["explainable-ai-sdk (>=1.0.0) ; python_version < \"3.13\"", "lit-nlp (==0.4.0) ; python_version < \"3.14\"", "pandas (>=1.0.0)", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\""] +lit = ["explainable-ai-sdk (>=1.0.0) ; python_version < \"3.13\"", "lit-nlp (==0.4.0) ; python_version < \"3.13\"", "pandas (>=1.0.0)", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\""] llama-index = ["llama-index", "llama-index-llms-google-genai", "openinference-instrumentation-llama-index (>=3.0,<4.0)"] llama-index-testing = ["absl-py", "cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "llama-index", "llama-index-llms-google-genai", "openinference-instrumentation-llama-index (>=3.0,<4.0)", "opentelemetry-exporter-gcp-logging (>=1.11.0a0,<2.0.0)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-exporter-otlp-proto-http (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.11.1,<3)", "pytest-xdist", "typing_extensions"] metadata = ["numpy (>=1.15.0)", "pandas (>=1.0.0)"] pipelines = ["pyyaml (>=5.3.1,<7)"] -prediction = ["docker (>=5.0.3)", "fastapi (>=0.71.0,<=0.114.0)", "httpx (>=0.23.0,<=0.28.1)", "starlette (>=0.17.1)", "uvicorn[standard] (>=0.16.0)"] +prediction = ["docker (>=5.0.3)", "fastapi (>=0.71.0,<=0.124.4)", "httpx (>=0.23.0,<=0.28.1)", "starlette (>=0.17.1)", "uvicorn[standard] (>=0.16.0)"] private-endpoints = ["requests (>=2.28.1)", "urllib3 (>=1.21.1,<1.27)"] ray = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "immutabledict", "pandas (>=1.0.0)", "pyarrow (>=6.0.1)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || ==2.33.* || >=2.42.dev0,<=2.42.0) ; python_version < \"3.11\"", "ray[default] (>=2.5,<=2.47.1) ; python_version == \"3.11\""] ray-testing = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "immutabledict", "pandas (>=1.0.0)", "pyarrow (>=6.0.1)", "pytest-xdist", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || ==2.33.* || >=2.42.dev0,<=2.42.0) ; python_version < \"3.11\"", "ray[default] (>=2.5,<=2.47.1) ; python_version == \"3.11\"", "ray[train]", "scikit-learn (<1.6.0)", "tensorflow ; python_version < \"3.13\"", "torch (>=2.0.0,<2.1.0)", "xgboost", "xgboost_ray"] reasoningengine = ["cloudpickle (>=3.0,<4.0)", "google-cloud-trace (<2)", "opentelemetry-exporter-gcp-logging (>=1.11.0a0,<2.0.0)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-exporter-otlp-proto-http (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.11.1,<3)", "typing_extensions"] tensorboard = ["tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "werkzeug (>=2.0.0,<4.0.0)"] -testing = ["Pillow", "aiohttp", "bigframes ; python_version >= \"3.10\" and python_version < \"3.14\"", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0) ; python_version < \"3.13\"", "fastapi (>=0.71.0,<=0.114.0)", "google-api-core (>=2.11,<3.0.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "google-vizier (>=0.1.6)", "grpcio-testing", "grpcio-tools (>=1.63.0) ; python_version >= \"3.13\"", "httpx (>=0.23.0,<=0.28.1)", "immutabledict", "immutabledict", "ipython", "jsonschema", "kfp (>=2.6.0,<3.0.0) ; python_version < \"3.13\"", "lit-nlp (==0.4.0) ; python_version < \"3.14\"", "litellm (>=1.72.4,!=1.77.2,!=1.77.3,!=1.77.4)", "mlflow (>=1.27.0) ; python_version >= \"3.13\"", "mlflow (>=1.27.0,<=2.16.0) ; python_version < \"3.13\"", "mock", "nltk", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "protobuf (<=5.29.4)", "pyarrow (>=10.0.1) ; python_version == \"3.11\"", "pyarrow (>=14.0.0) ; python_version >= \"3.12\"", "pyarrow (>=3.0.0,<8.0.0) ; python_version < \"3.11\"", "pyarrow (>=6.0.1)", "pytest-asyncio", "pytest-cov", "pytest-xdist", "pyyaml", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || ==2.33.* || >=2.42.dev0,<=2.42.0) ; python_version < \"3.11\"", "ray[default] (>=2.5,<=2.47.1) ; python_version == \"3.11\"", "requests (>=2.28.1)", "requests-toolbelt (<=1.0.0)", "requests-toolbelt (<=1.0.0)", "ruamel.yaml", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "sentencepiece (>=0.2.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (==2.14.1) ; python_version <= \"3.11\"", "tensorflow (==2.19.0) ; python_version > \"3.11\" and python_version < \"3.13\"", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "torch (>=2.0.0,<2.1.0) ; python_version <= \"3.11\"", "torch (>=2.2.0) ; python_version > \"3.11\" and python_version < \"3.13\"", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<4.0.0)", "werkzeug (>=2.0.0,<4.0.0)", "xgboost"] +testing = ["Pillow", "aiohttp", "bigframes ; python_version >= \"3.10\" and python_version < \"3.14\"", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0) ; python_version < \"3.13\"", "fastapi (>=0.71.0,<=0.124.4)", "google-api-core (>=2.11,<3.0.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-vizier (>=0.1.6)", "google-vizier (>=0.1.6)", "grpcio-testing", "grpcio-tools (>=1.63.0) ; python_version >= \"3.13\"", "httpx (>=0.23.0,<=0.28.1)", "immutabledict", "immutabledict", "ipython", "jsonschema", "kfp (>=2.6.0,<3.0.0) ; python_version < \"3.13\"", "lit-nlp (==0.4.0) ; python_version < \"3.13\"", "litellm (>=1.72.4,!=1.77.2,!=1.77.3,!=1.77.4)", "mlflow (>=1.27.0) ; python_version >= \"3.13\"", "mlflow (>=1.27.0,<=2.16.0) ; python_version < \"3.13\"", "mock", "nltk", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "protobuf (<=5.29.4)", "pyarrow (>=10.0.1) ; python_version == \"3.11\"", "pyarrow (>=14.0.0) ; python_version >= \"3.12\"", "pyarrow (>=3.0.0,<8.0.0) ; python_version < \"3.11\"", "pyarrow (>=6.0.1)", "pytest-asyncio", "pytest-cov", "pytest-xdist", "pyyaml", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<2.10.dev0 || ==2.33.* || >=2.42.dev0,<=2.42.0) ; python_version < \"3.11\"", "ray[default] (>=2.5,<=2.47.1) ; python_version == \"3.11\"", "requests (>=2.28.1)", "requests-toolbelt (<=1.0.0)", "requests-toolbelt (<=1.0.0)", "ruamel.yaml", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn (<1.6.0) ; python_version <= \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "scikit-learn ; python_version > \"3.10\"", "sentencepiece (>=0.2.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorboard-plugin-profile (>=2.4.0,<2.18.0)", "tensorflow (==2.14.1) ; python_version <= \"3.11\"", "tensorflow (==2.19.0) ; python_version > \"3.11\" and python_version < \"3.13\"", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\"", "torch (>=2.0.0,<2.1.0) ; python_version <= \"3.11\"", "torch (>=2.2.0) ; python_version > \"3.11\" and python_version < \"3.13\"", "tqdm (>=4.23.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<4.0.0)", "werkzeug (>=2.0.0,<4.0.0)", "xgboost"] tokenization = ["sentencepiece (>=0.2.0)"] vizier = ["google-vizier (>=0.1.6)"] xai = ["tensorflow (>=2.3.0,<3.0.0) ; python_version < \"3.13\""] @@ -2039,25 +2072,21 @@ grpc = ["grpcio (>=1.38.0,<2.0.0) ; python_version < \"3.14\"", "grpcio (>=1.75. [[package]] name = "google-cloud-iam" -version = "2.20.0" +version = "2.19.1" description = "Google Cloud Iam API client library" optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"extra-proxy\"" files = [ - {file = "google_cloud_iam-2.20.0-py3-none-any.whl", hash = "sha256:643fcf6db3100772f222c7173bc1af15541a05ec1c43785191e835146ed150b8"}, - {file = "google_cloud_iam-2.20.0.tar.gz", hash = "sha256:06568ed8313f59fac46d21a5aae4c54eb1dda9f6bcecf2736c58ab1065dc9173"}, + {file = "google_cloud_iam-2.19.1-py3-none-any.whl", hash = "sha256:11b08b86d82510021f9dd9f0beb5a08219e070deab09e28d4c0ce49f8c70997d"}, + {file = "google_cloud_iam-2.19.1.tar.gz", hash = "sha256:f059c369ad98af6be3401f0f5d087775d775fb96833be1e9ab8048c422fb1bf4"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0" grpc-google-iam-v1 = ">=0.12.4,<1.0.0" -grpcio = [ - {version = ">=1.33.2,<2.0.0"}, - {version = ">=1.75.1,<2.0.0", markers = "python_version >= \"3.14\""}, -] proto-plus = [ {version = ">=1.22.3,<2.0.0"}, {version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""}, @@ -2143,7 +2172,7 @@ description = "Google Cloud Storage API client library" optional = true python-versions = ">=3.7" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"google\"" +markers = "extra == \"google\" and python_version < \"3.14\"" files = [ {file = "google_cloud_storage-3.8.0-py3-none-any.whl", hash = "sha256:78cfeae7cac2ca9441d0d0271c2eb4ebfa21aa4c6944dd0ccac0389e81d955a7"}, {file = "google_cloud_storage-3.8.0.tar.gz", hash = "sha256:cc67952dce84ebc9d44970e24647a58260630b7b64d72360cedaf422d6727f28"}, @@ -2494,7 +2523,7 @@ files = [ {file = "grpcio-1.76.0-cp39-cp39-win_amd64.whl", hash = "sha256:acab0277c40eff7143c2323190ea57b9ee5fd353d8190ee9652369fae735668a"}, {file = "grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73"}, ] -markers = {main = "(python_version <= \"3.13\" or extra == \"google\" or extra == \"extra-proxy\" or extra == \"grpc\") and (extra == \"extra-proxy\" or extra == \"google\" or extra == \"grpc\")"} +markers = {main = "(python_version <= \"3.12\" or extra == \"google\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"google\") and python_version >= \"3.10\"", dev = "python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} [package.dependencies] typing-extensions = ">=4.12,<5.0" @@ -2502,6 +2531,84 @@ typing-extensions = ">=4.12,<5.0" [package.extras] protobuf = ["grpcio-tools (>=1.76.0)"] +[[package]] +name = "grpcio" +version = "1.80.0" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev", "proxy-dev"] +files = [ + {file = "grpcio-1.80.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:886457a7768e408cdce226ad1ca67d2958917d306523a0e21e1a2fdaa75c9c9c"}, + {file = "grpcio-1.80.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:7b641fc3f1dc647bfd80bd713addc68f6d145956f64677e56d9ebafc0bd72388"}, + {file = "grpcio-1.80.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:33eb763f18f006dc7fee1e69831d38d23f5eccd15b2e0f92a13ee1d9242e5e02"}, + {file = "grpcio-1.80.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:52d143637e3872633fc7dd7c3c6a1c84e396b359f3a72e215f8bf69fd82084fc"}, + {file = "grpcio-1.80.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c51bf8ac4575af2e0678bccfb07e47321fc7acb5049b4482832c5c195e04e13a"}, + {file = "grpcio-1.80.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:50a9871536d71c4fba24ee856abc03a87764570f0c457dd8db0b4018f379fed9"}, + {file = "grpcio-1.80.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a72d84ad0514db063e21887fbacd1fd7acb4d494a564cae22227cd45c7fbf199"}, + {file = "grpcio-1.80.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f7691a6788ad9196872f95716df5bc643ebba13c97140b7a5ee5c8e75d1dea81"}, + {file = "grpcio-1.80.0-cp310-cp310-win32.whl", hash = "sha256:46c2390b59d67f84e882694d489f5b45707c657832d7934859ceb8c33f467069"}, + {file = "grpcio-1.80.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc053420fc75749c961e2a4c906398d7c15725d36ccc04ae6d16093167223b58"}, + {file = "grpcio-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a"}, + {file = "grpcio-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060"}, + {file = "grpcio-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2"}, + {file = "grpcio-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21"}, + {file = "grpcio-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab"}, + {file = "grpcio-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1"}, + {file = "grpcio-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106"}, + {file = "grpcio-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6"}, + {file = "grpcio-1.80.0-cp311-cp311-win32.whl", hash = "sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440"}, + {file = "grpcio-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9"}, + {file = "grpcio-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0"}, + {file = "grpcio-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2"}, + {file = "grpcio-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de"}, + {file = "grpcio-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921"}, + {file = "grpcio-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411"}, + {file = "grpcio-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd"}, + {file = "grpcio-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f"}, + {file = "grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f"}, + {file = "grpcio-1.80.0-cp312-cp312-win32.whl", hash = "sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193"}, + {file = "grpcio-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff"}, + {file = "grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad"}, + {file = "grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0"}, + {file = "grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f"}, + {file = "grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6"}, + {file = "grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140"}, + {file = "grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d"}, + {file = "grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7"}, + {file = "grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7"}, + {file = "grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294"}, + {file = "grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50"}, + {file = "grpcio-1.80.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e"}, + {file = "grpcio-1.80.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f"}, + {file = "grpcio-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9"}, + {file = "grpcio-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14"}, + {file = "grpcio-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05"}, + {file = "grpcio-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1"}, + {file = "grpcio-1.80.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f"}, + {file = "grpcio-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e"}, + {file = "grpcio-1.80.0-cp314-cp314-win32.whl", hash = "sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae"}, + {file = "grpcio-1.80.0-cp314-cp314-win_amd64.whl", hash = "sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f"}, + {file = "grpcio-1.80.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:aacdfb4ed3eb919ca997504d27e03d5dba403c85130b8ed450308590a738f7a4"}, + {file = "grpcio-1.80.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:a361c20ec1ccd3c3953d20fb6d7b4125093bdd10dff44c5e2bbb39e58917cedc"}, + {file = "grpcio-1.80.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:43168871f170d1e4ed16ae03d10cd21efa29f190e710a624cee7e5ae07da6f4f"}, + {file = "grpcio-1.80.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1b97cd29a8eda100b559b455331c487a80915b6ea6bd91cf3e89836c4ee8d957"}, + {file = "grpcio-1.80.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bac1d573dfa84ce59a5547073e28fa7326d53352adda6912e362da0b917fcef4"}, + {file = "grpcio-1.80.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4560cf0e86514595dbbd330cd65b7afad4b5c4b8c4905c041cfffa138d45e6fd"}, + {file = "grpcio-1.80.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec0a592e926071b4abad50c1495cd0d0d513324b3ff5e7267067c33ba27506e4"}, + {file = "grpcio-1.80.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:deb10a1528473c11f72a0939eed36d83e847d7cbb63e8cc5611fb7a912d38614"}, + {file = "grpcio-1.80.0-cp39-cp39-win32.whl", hash = "sha256:627fb7312171cdc52828bd6fac8d7028ff2a64b89f1957b6f3416caa2218d141"}, + {file = "grpcio-1.80.0-cp39-cp39-win_amd64.whl", hash = "sha256:05d55e1798756282cddd52d56c896b3e7d673e3a8798c2f1cd05ba249a3bb4de"}, + {file = "grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257"}, +] +markers = {main = "extra == \"extra-proxy\" or extra == \"google\" or extra == \"grpc\""} + +[package.dependencies] +typing-extensions = ">=4.12,<5.0" + +[package.extras] +protobuf = ["grpcio-tools (>=1.80.0)"] + [[package]] name = "grpcio-status" version = "1.62.3" @@ -2750,29 +2857,31 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve [[package]] name = "hypercorn" -version = "0.15.0" +version = "0.17.3" description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["proxy-dev"] files = [ - {file = "hypercorn-0.15.0-py3-none-any.whl", hash = "sha256:5008944999612fd188d7a1ca02e89d20065642b89503020ac392dfed11840730"}, - {file = "hypercorn-0.15.0.tar.gz", hash = "sha256:d517f68d5dc7afa9a9d50ecefb0f769f466ebe8c1c18d2c2f447a24e763c9a63"}, + {file = "hypercorn-0.17.3-py3-none-any.whl", hash = "sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"}, + {file = "hypercorn-0.17.3.tar.gz", hash = "sha256:1b37802ee3ac52d2d85270700d565787ab16cf19e1462ccfa9f089ca17574165"}, ] [package.dependencies] +exceptiongroup = {version = ">=1.1.0", markers = "python_version < \"3.11\""} h11 = "*" h2 = ">=3.1.0" priority = "*" taskgroup = {version = "*", markers = "python_version < \"3.11\""} tomli = {version = "*", markers = "python_version < \"3.11\""} +typing_extensions = {version = "*", markers = "python_version < \"3.11\""} wsproto = ">=0.14.0" [package.extras] docs = ["pydata_sphinx_theme", "sphinxcontrib_mermaid"] h3 = ["aioquic (>=0.9.0,<1.0)"] -trio = ["exceptiongroup (>=1.1.0)", "trio (>=0.22.0)"] -uvloop = ["uvloop ; platform_system != \"Windows\""] +trio = ["trio (>=0.22.0)"] +uvloop = ["uvloop (>=0.18) ; platform_system != \"Windows\""] [[package]] name = "hyperframe" @@ -2816,23 +2925,27 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.1.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" groups = ["main", "dev", "proxy-dev"] files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -3030,14 +3143,14 @@ files = [ [[package]] name = "jsonschema" -version = "4.25.1" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, - {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] @@ -3048,7 +3161,7 @@ rpds-py = ">=0.7.1" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" @@ -3179,14 +3292,14 @@ files = [ [[package]] name = "langfuse" -version = "2.60.10" +version = "2.59.7" description = "A client library for accessing langfuse" optional = false python-versions = "<4.0,>=3.9" groups = ["dev"] files = [ - {file = "langfuse-2.60.10-py3-none-any.whl", hash = "sha256:815c6369194aa5b2a24f88eb9952f7c3fc863272c41e90642a71f3bc76f4a11f"}, - {file = "langfuse-2.60.10.tar.gz", hash = "sha256:a26d0d927a28ee01b2d12bb5b862590b643cc4e60a28de6e2b0c2cfff5dbfc6a"}, + {file = "langfuse-2.59.7-py3-none-any.whl", hash = "sha256:2c6890f5b842257173eb54d08f2890c7fd7617859a48b3914ef73f13a6514473"}, + {file = "langfuse-2.59.7.tar.gz", hash = "sha256:f631981705177bf53d030d191397da9b864b99729a7273448afed10d76f78e23"}, ] [package.dependencies] @@ -3204,6 +3317,106 @@ langchain = ["langchain (>=0.0.309)"] llama-index = ["llama-index (>=0.10.12,<2.0.0)"] openai = ["openai (>=0.27.8)"] +[[package]] +name = "librt" +version = "0.8.1" +description = "Mypyc runtime library" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "librt-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81fd938344fecb9373ba1b155968c8a329491d2ce38e7ddb76f30ffb938f12dc"}, + {file = "librt-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5db05697c82b3a2ec53f6e72b2ed373132b0c2e05135f0696784e97d7f5d48e7"}, + {file = "librt-0.8.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d56bc4011975f7460bea7b33e1ff425d2f1adf419935ff6707273c77f8a4ada6"}, + {file = "librt-0.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdc0f588ff4b663ea96c26d2a230c525c6fc62b28314edaaaca8ed5af931ad0"}, + {file = "librt-0.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c2b54ff6717a7a563b72627990bec60d8029df17df423f0ed37d56a17a176b"}, + {file = "librt-0.8.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f1125e6bbf2f1657d9a2f3ccc4a2c9b0c8b176965bb565dd4d86be67eddb4b6"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f4bb453f408137d7581be309b2fbc6868a80e7ef60c88e689078ee3a296ae71"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c336d61d2fe74a3195edc1646d53ff1cddd3a9600b09fa6ab75e5514ba4862a7"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:eb5656019db7c4deacf0c1a55a898c5bb8f989be904597fcb5232a2f4828fa05"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c25d9e338d5bed46c1632f851babf3d13c78f49a225462017cf5e11e845c5891"}, + {file = "librt-0.8.1-cp310-cp310-win32.whl", hash = "sha256:aaab0e307e344cb28d800957ef3ec16605146ef0e59e059a60a176d19543d1b7"}, + {file = "librt-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:56e04c14b696300d47b3bc5f1d10a00e86ae978886d0cee14e5714fafb5df5d2"}, + {file = "librt-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:681dc2451d6d846794a828c16c22dc452d924e9f700a485b7ecb887a30aad1fd"}, + {file = "librt-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3b4350b13cc0e6f5bec8fa7caf29a8fb8cdc051a3bae45cfbfd7ce64f009965"}, + {file = "librt-0.8.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ac1e7817fd0ed3d14fd7c5df91daed84c48e4c2a11ee99c0547f9f62fdae13da"}, + {file = "librt-0.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:747328be0c5b7075cde86a0e09d7a9196029800ba75a1689332348e998fb85c0"}, + {file = "librt-0.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0af2bd2bc204fa27f3d6711d0f360e6b8c684a035206257a81673ab924aa11e"}, + {file = "librt-0.8.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d480de377f5b687b6b1bc0c0407426da556e2a757633cc7e4d2e1a057aa688f3"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d0ee06b5b5291f609ddb37b9750985b27bc567791bc87c76a569b3feed8481ac"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e2c6f77b9ad48ce5603b83b7da9ee3e36b3ab425353f695cba13200c5d96596"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:439352ba9373f11cb8e1933da194dcc6206daf779ff8df0ed69c5e39113e6a99"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:82210adabbc331dbb65d7868b105185464ef13f56f7f76688565ad79f648b0fe"}, + {file = "librt-0.8.1-cp311-cp311-win32.whl", hash = "sha256:52c224e14614b750c0a6d97368e16804a98c684657c7518752c356834fff83bb"}, + {file = "librt-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:c00e5c884f528c9932d278d5c9cbbea38a6b81eb62c02e06ae53751a83a4d52b"}, + {file = "librt-0.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:f7cdf7f26c2286ffb02e46d7bac56c94655540b26347673bea15fa52a6af17e9"}, + {file = "librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a"}, + {file = "librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9"}, + {file = "librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb"}, + {file = "librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d"}, + {file = "librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7"}, + {file = "librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0"}, + {file = "librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a"}, + {file = "librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444"}, + {file = "librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d"}, + {file = "librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35"}, + {file = "librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583"}, + {file = "librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c"}, + {file = "librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04"}, + {file = "librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363"}, + {file = "librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d"}, + {file = "librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a"}, + {file = "librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79"}, + {file = "librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0"}, + {file = "librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f"}, + {file = "librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c"}, + {file = "librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc"}, + {file = "librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c"}, + {file = "librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3"}, + {file = "librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78"}, + {file = "librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023"}, + {file = "librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730"}, + {file = "librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3"}, + {file = "librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1"}, + {file = "librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994"}, + {file = "librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a"}, + {file = "librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4"}, + {file = "librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61"}, + {file = "librt-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3dff3d3ca8db20e783b1bc7de49c0a2ab0b8387f31236d6a026597d07fcd68ac"}, + {file = "librt-0.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08eec3a1fc435f0d09c87b6bf1ec798986a3544f446b864e4099633a56fcd9ed"}, + {file = "librt-0.8.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e3f0a41487fd5fad7e760b9e8a90e251e27c2816fbc2cff36a22a0e6bcbbd9dd"}, + {file = "librt-0.8.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bacdb58d9939d95cc557b4dbaa86527c9db2ac1ed76a18bc8d26f6dc8647d851"}, + {file = "librt-0.8.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d7ab1f01aa753188605b09a51faa44a3327400b00b8cce424c71910fc0a128"}, + {file = "librt-0.8.1-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4998009e7cb9e896569f4be7004f09d0ed70d386fa99d42b6d363f6d200501ac"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2cc68eeeef5e906839c7bb0815748b5b0a974ec27125beefc0f942715785b551"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0bf69d79a23f4f40b8673a947a234baeeb133b5078b483b7297c5916539cf5d5"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:22b46eabd76c1986ee7d231b0765ad387d7673bbd996aa0d0d054b38ac65d8f6"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:237796479f4d0637d6b9cbcb926ff424a97735e68ade6facf402df4ec93375ed"}, + {file = "librt-0.8.1-cp39-cp39-win32.whl", hash = "sha256:4beb04b8c66c6ae62f8c1e0b2f097c1ebad9295c929a8d5286c05eae7c2fc7dc"}, + {file = "librt-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:64548cde61b692dc0dc379f4b5f59a2f582c2ebe7890d09c1ae3b9e66fa015b7"}, + {file = "librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73"}, +] + [[package]] name = "litellm-enterprise" version = "0.1.35" @@ -3588,15 +3801,15 @@ dev = ["absl-py", "pyink", "pylint (>=2.6.0)", "pytest", "pytest-xdist"] [[package]] name = "mlflow" -version = "3.6.0" +version = "3.9.0" description = "MLflow is an open source platform for the complete machine learning lifecycle" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and extra == \"mlflow\"" files = [ - {file = "mlflow-3.6.0-py3-none-any.whl", hash = "sha256:04d1691facd412be8e61b963fad859286cfeb2dbcafaea294e6aa0b83a15fc04"}, - {file = "mlflow-3.6.0.tar.gz", hash = "sha256:d945d259b5c6b551a9f26846db8979fd84c78114a027b77ada3298f821a9b0e1"}, + {file = "mlflow-3.9.0-py3-none-any.whl", hash = "sha256:280f94854e5ece42fc5538180b276661c62dbfb2c848a98e8873e78915379ac6"}, + {file = "mlflow-3.9.0.tar.gz", hash = "sha256:47a41fa22107b0ceee1f91e2184759ebfaffa31d7913b70318b78fb5369e52ec"}, ] [package.dependencies] @@ -3607,15 +3820,16 @@ Flask = "<4" Flask-CORS = "<7" graphene = "<4" gunicorn = {version = "<24", markers = "platform_system != \"Windows\""} -huey = ">=2.5.0,<3" +huey = ">=2.5.4,<3" matplotlib = "<4" -mlflow-skinny = "3.6.0" -mlflow-tracing = "3.6.0" +mlflow-skinny = "3.9.0" +mlflow-tracing = "3.9.0" numpy = "<3" pandas = "<3" pyarrow = ">=4.0.0,<23" scikit-learn = "<2" scipy = "<2" +skops = "<1" sqlalchemy = ">=1.4.0,<3" waitress = {version = "<4", markers = "platform_system == \"Windows\""} @@ -3623,26 +3837,27 @@ waitress = {version = "<4", markers = "platform_system == \"Windows\""} aliyun-oss = ["aliyunstoreplugin"] auth = ["Flask-WTF (<2)"] databricks = ["azure-storage-file-datalake (>12)", "boto3 (>1)", "botocore", "databricks-agents (>=1.2.0,<2.0)", "google-cloud-storage (>=1.30.0)"] +db = ["PyMySQL", "psycopg2-binary", "pymssql"] extras = ["azureml-core (>=1.2.0)", "boto3", "botocore", "google-cloud-storage (>=1.30.0)", "kubernetes", "prometheus-flask-exporter", "pyarrow", "pysftp", "requests-auth-aws-sigv4", "virtualenv"] gateway = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<2)"] -genai = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<2)"] +genai = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "litellm (>=1.0.0,<2)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<2)"] jfrog = ["mlflow-jfrog-plugin"] -langchain = ["langchain (>=0.3.7,<=0.3.27)"] -mcp = ["fastmcp (>=2.0.0,<3)"] +langchain = ["langchain (>=0.3.15,<=1.2.3)"] +mcp = ["click (!=8.3.0)", "fastmcp (>=2.0.0,<3)"] mlserver = ["mlserver (>=1.2.0,!=1.3.1,<2.0.0)", "mlserver-mlflow (>=1.2.0,!=1.3.1,<2.0.0)"] sqlserver = ["mlflow-dbstore"] [[package]] name = "mlflow-skinny" -version = "3.6.0" +version = "3.9.0" description = "MLflow is an open source platform for the complete machine learning lifecycle" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and extra == \"mlflow\"" files = [ - {file = "mlflow_skinny-3.6.0-py3-none-any.whl", hash = "sha256:c83b34fce592acb2cc6bddcb507587a6d9ef3f590d9e7a8658c85e0980596d78"}, - {file = "mlflow_skinny-3.6.0.tar.gz", hash = "sha256:cc04706b5b6faace9faf95302a6e04119485e1bfe98ddc9b85b81984e80944b6"}, + {file = "mlflow_skinny-3.9.0-py3-none-any.whl", hash = "sha256:9b98706cdf9e07a61da7fbcd717c8d35ac89c76e084d25aafdbc150028e832d5"}, + {file = "mlflow_skinny-3.9.0.tar.gz", hash = "sha256:0598e0635dd1af9d195fb429210819aa4b56e9d6014f87134241f2325d57a290"}, ] [package.dependencies] @@ -3670,26 +3885,27 @@ uvicorn = "<1" aliyun-oss = ["aliyunstoreplugin"] auth = ["Flask-WTF (<2)"] databricks = ["azure-storage-file-datalake (>12)", "boto3 (>1)", "botocore", "databricks-agents (>=1.2.0,<2.0)", "google-cloud-storage (>=1.30.0)"] +db = ["PyMySQL", "psycopg2-binary", "pymssql"] extras = ["azureml-core (>=1.2.0)", "boto3", "botocore", "google-cloud-storage (>=1.30.0)", "kubernetes", "prometheus-flask-exporter", "pyarrow", "pysftp", "requests-auth-aws-sigv4", "virtualenv"] gateway = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<2)"] -genai = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<2)"] +genai = ["aiohttp (<4)", "boto3 (>=1.28.56,<2)", "fastapi (<1)", "litellm (>=1.0.0,<2)", "slowapi (>=0.1.9,<1)", "tiktoken (<1)", "uvicorn[standard] (<1)", "watchfiles (<2)"] jfrog = ["mlflow-jfrog-plugin"] -langchain = ["langchain (>=0.3.7,<=0.3.27)"] -mcp = ["fastmcp (>=2.0.0,<3)"] +langchain = ["langchain (>=0.3.15,<=1.2.3)"] +mcp = ["click (!=8.3.0)", "fastmcp (>=2.0.0,<3)"] mlserver = ["mlserver (>=1.2.0,!=1.3.1,<2.0.0)", "mlserver-mlflow (>=1.2.0,!=1.3.1,<2.0.0)"] sqlserver = ["mlflow-dbstore"] [[package]] name = "mlflow-tracing" -version = "3.6.0" +version = "3.9.0" description = "MLflow Tracing SDK is an open-source, lightweight Python package that only includes the minimum set of dependencies and functionality to instrument your code/models/agents with MLflow Tracing." optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and extra == \"mlflow\"" files = [ - {file = "mlflow_tracing-3.6.0-py3-none-any.whl", hash = "sha256:a68ff03ba5129c67dc98e6871e0d5ef512dd3ee66d01e1c1a0c946c08a6d4755"}, - {file = "mlflow_tracing-3.6.0.tar.gz", hash = "sha256:ccff80b3aad6caa18233c98ba69922a91a6f914e0a13d12e1977af7523523d4c"}, + {file = "mlflow_tracing-3.9.0-py3-none-any.whl", hash = "sha256:93df8df0697303ad3135df6228934e5d9d2f264d2683b97a6f06ad865ec418a0"}, + {file = "mlflow_tracing-3.9.0.tar.gz", hash = "sha256:3a0676e6f362712299d191108a5cbcd596f6d84f23f050dfbf80161e245d456c"}, ] [package.dependencies] @@ -3704,14 +3920,14 @@ pydantic = ">=2.0.0,<3" [[package]] name = "msal" -version = "1.34.0" +version = "1.35.1" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.8" groups = ["main", "proxy-dev"] files = [ - {file = "msal-1.34.0-py3-none-any.whl", hash = "sha256:f669b1644e4950115da7a176441b0e13ec2975c29528d8b9e81316023676d6e1"}, - {file = "msal-1.34.0.tar.gz", hash = "sha256:76ba83b716ea5a6d75b0279c0ac353a0e05b820ca1f6682c0eb7f45190c43c2f"}, + {file = "msal-1.35.1-py3-none-any.whl", hash = "sha256:8f4e82f34b10c19e326ec69f44dc6b30171f2f7098f3720ea8a9f0c11832caa3"}, + {file = "msal-1.35.1.tar.gz", hash = "sha256:70cac18ab80a053bff86219ba64cfe3da1f307c74b009e2da57ef040eb1b5656"}, ] [package.dependencies] @@ -3720,7 +3936,7 @@ PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" [package.extras] -broker = ["pymsalruntime (>=0.14,<0.19) ; python_version >= \"3.6\" and platform_system == \"Windows\"", "pymsalruntime (>=0.17,<0.19) ; python_version >= \"3.8\" and platform_system == \"Darwin\"", "pymsalruntime (>=0.18,<0.19) ; python_version >= \"3.8\" and platform_system == \"Linux\""] +broker = ["pymsalruntime (>=0.14,<0.21) ; python_version >= \"3.8\" and platform_system == \"Windows\"", "pymsalruntime (>=0.17,<0.21) ; python_version >= \"3.8\" and platform_system == \"Darwin\"", "pymsalruntime (>=0.18,<0.21) ; python_version >= \"3.8\" and platform_system == \"Linux\""] [[package]] name = "msal-extensions" @@ -3901,53 +4117,54 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} [[package]] name = "mypy" -version = "1.18.2" +version = "1.19.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, - {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, - {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, - {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, - {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, - {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, - {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, - {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, - {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, - {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, - {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, - {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, - {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, - {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, - {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, - {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, - {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, - {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, - {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, - {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, - {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, - {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, - {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, - {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, - {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, - {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, - {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, - {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, - {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, - {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, - {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, - {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, - {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, - {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, - {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, - {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, - {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, - {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, + {file = "mypy-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6148ede033982a8c5ca1143de34c71836a09f105068aaa8b7d5edab2b053e6c8"}, + {file = "mypy-1.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a9ac09e52bb0f7fb912f5d2a783345c72441a08ef56ce3e17c1752af36340a39"}, + {file = "mypy-1.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f7254c15ab3f8ed68f8e8f5cbe88757848df793e31c36aaa4d4f9783fd08ab"}, + {file = "mypy-1.19.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318ba74f75899b0e78b847d8c50821e4c9637c79d9a59680fc1259f29338cb3e"}, + {file = "mypy-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf7d84f497f78b682edd407f14a7b6e1a2212b433eedb054e2081380b7395aa3"}, + {file = "mypy-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:c3385246593ac2b97f155a0e9639be906e73534630f663747c71908dfbf26134"}, + {file = "mypy-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a31e4c28e8ddb042c84c5e977e28a21195d086aaffaf08b016b78e19c9ef8106"}, + {file = "mypy-1.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34ec1ac66d31644f194b7c163d7f8b8434f1b49719d403a5d26c87fff7e913f7"}, + {file = "mypy-1.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb64b0ba5980466a0f3f9990d1c582bcab8db12e29815ecb57f1408d99b4bff7"}, + {file = "mypy-1.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:120cffe120cca5c23c03c77f84abc0c14c5d2e03736f6c312480020082f1994b"}, + {file = "mypy-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7a500ab5c444268a70565e374fc803972bfd1f09545b13418a5174e29883dab7"}, + {file = "mypy-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:c14a98bc63fd867530e8ec82f217dae29d0550c86e70debc9667fff1ec83284e"}, + {file = "mypy-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0fb3115cb8fa7c5f887c8a8d81ccdcb94cff334684980d847e5a62e926910e1d"}, + {file = "mypy-1.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3e19e3b897562276bb331074d64c076dbdd3e79213f36eed4e592272dabd760"}, + {file = "mypy-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9d491295825182fba01b6ffe2c6fe4e5a49dbf4e2bb4d1217b6ced3b4797bc6"}, + {file = "mypy-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6016c52ab209919b46169651b362068f632efcd5eb8ef9d1735f6f86da7853b2"}, + {file = "mypy-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f188dcf16483b3e59f9278c4ed939ec0254aa8a60e8fc100648d9ab5ee95a431"}, + {file = "mypy-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:0e3c3d1e1d62e678c339e7ade72746a9e0325de42cd2cccc51616c7b2ed1a018"}, + {file = "mypy-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7686ed65dbabd24d20066f3115018d2dce030d8fa9db01aa9f0a59b6813e9f9e"}, + {file = "mypy-1.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4a985b2e32f23bead72e2fb4bbe5d6aceee176be471243bd831d5b2644672d"}, + {file = "mypy-1.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc51a5b864f73a3a182584b1ac75c404396a17eced54341629d8bdcb644a5bba"}, + {file = "mypy-1.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37af5166f9475872034b56c5efdcf65ee25394e9e1d172907b84577120714364"}, + {file = "mypy-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:510c014b722308c9bd377993bcbf9a07d7e0692e5fa8fc70e639c1eb19fc6bee"}, + {file = "mypy-1.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:cabbee74f29aa9cd3b444ec2f1e4fa5a9d0d746ce7567a6a609e224429781f53"}, + {file = "mypy-1.19.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f2e36bed3c6d9b5f35d28b63ca4b727cb0228e480826ffc8953d1892ddc8999d"}, + {file = "mypy-1.19.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a18d8abdda14035c5718acb748faec09571432811af129bf0d9e7b2d6699bf18"}, + {file = "mypy-1.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75e60aca3723a23511948539b0d7ed514dda194bc3755eae0bfc7a6b4887aa7"}, + {file = "mypy-1.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f44f2ae3c58421ee05fe609160343c25f70e3967f6e32792b5a78006a9d850f"}, + {file = "mypy-1.19.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63ea6a00e4bd6822adbfc75b02ab3653a17c02c4347f5bb0cf1d5b9df3a05835"}, + {file = "mypy-1.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ad925b14a0bb99821ff6f734553294aa6a3440a8cb082fe1f5b84dfb662afb1"}, + {file = "mypy-1.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0dde5cb375cb94deff0d4b548b993bec52859d1651e073d63a1386d392a95495"}, + {file = "mypy-1.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1cf9c59398db1c68a134b0b5354a09a1e124523f00bacd68e553b8bd16ff3299"}, + {file = "mypy-1.19.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3210d87b30e6af9c8faed61be2642fcbe60ef77cec64fa1ef810a630a4cf671c"}, + {file = "mypy-1.19.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2c1101ab41d01303103ab6ef82cbbfedb81c1a060c868fa7cc013d573d37ab5"}, + {file = "mypy-1.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ea4fd21bb48f0da49e6d3b37ef6bd7e8228b9fe41bbf4d80d9364d11adbd43c"}, + {file = "mypy-1.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:16f76ff3f3fd8137aadf593cb4607d82634fca675e8211ad75c43d86033ee6c6"}, + {file = "mypy-1.19.0-py3-none-any.whl", hash = "sha256:0c01c99d626380752e527d5ce8e69ffbba2046eb8a060db0329690849cf9b6f9"}, + {file = "mypy-1.19.0.tar.gz", hash = "sha256:f6b874ca77f733222641e5c46e4711648c4037ea13646fd0cdc814c2eaec2528"}, ] [package.dependencies] +librt = ">=0.6.2" mypy_extensions = ">=1.0.0" pathspec = ">=0.9.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} @@ -3991,7 +4208,7 @@ description = "Fundamental package for array computing in Python" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "(python_version < \"3.14\" or extra == \"mlflow\" or extra == \"google\") and (python_version <= \"3.13\" or extra == \"mlflow\" or extra == \"google\" or extra == \"extra-proxy\" or extra == \"semantic-router\") and (python_version < \"3.13\" or extra == \"extra-proxy\" or extra == \"google\" or extra == \"semantic-router\" or extra == \"mlflow\") and (python_version >= \"3.10\" or extra == \"extra-proxy\" or extra == \"semantic-router\" or extra == \"google\") and (extra == \"extra-proxy\" or extra == \"semantic-router\" or extra == \"google\" or extra == \"mlflow\")" +markers = "(python_version < \"3.14\" or extra == \"mlflow\") and (extra == \"mlflow\" or extra == \"extra-proxy\" or extra == \"semantic-router\") and (python_version >= \"3.10\" or extra == \"extra-proxy\" or extra == \"semantic-router\")" files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -4033,21 +4250,27 @@ files = [ [[package]] name = "numpydoc" -version = "1.9.0" +version = "1.8.0" description = "Sphinx extension to support docstrings in Numpy format" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"utils\"" files = [ - {file = "numpydoc-1.9.0-py3-none-any.whl", hash = "sha256:8a2983b2d62bfd0a8c470c7caa25e7e0c3d163875cdec12a8a1034020a9d1135"}, - {file = "numpydoc-1.9.0.tar.gz", hash = "sha256:5fec64908fe041acc4b3afc2a32c49aab1540cf581876f5563d68bb129e27c5b"}, + {file = "numpydoc-1.8.0-py3-none-any.whl", hash = "sha256:72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541"}, + {file = "numpydoc-1.8.0.tar.gz", hash = "sha256:022390ab7464a44f8737f79f8b31ce1d3cfa4b4af79ccaa1aac5e8368db587fb"}, ] [package.dependencies] sphinx = ">=6" +tabulate = ">=0.8.10" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +[package.extras] +developer = ["pre-commit (>=3.3)", "tomli ; python_version < \"3.11\""] +doc = ["intersphinx-registry", "matplotlib (>=3.5)", "numpy (>=1.22)", "pydata-sphinx-theme (>=0.13.3)", "sphinx (>=7)"] +test = ["matplotlib", "pytest", "pytest-cov"] + [[package]] name = "oauthlib" version = "3.3.1" @@ -4068,14 +4291,14 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openai" -version = "2.8.1" +version = "2.30.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463"}, - {file = "openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f"}, + {file = "openai-2.30.0-py3-none-any.whl", hash = "sha256:9a5ae616888eb2748ec5e0c5b955a51592e0b201a11f4262db920f2a78c5231d"}, + {file = "openai-2.30.0.tar.gz", hash = "sha256:92f7661c990bda4b22a941806c83eabe4896c3094465030dd882a71abe80c885"}, ] [package.dependencies] @@ -4086,7 +4309,7 @@ jiter = ">=0.10.0,<1" pydantic = ">=1.9.0,<3" sniffio = "*" tqdm = ">4" -typing-extensions = ">=4.11,<5" +typing-extensions = ">=4.14,<5" [package.extras] aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.9)"] @@ -4096,250 +4319,233 @@ voice-helpers = ["numpy (>=2.0.2)", "sounddevice (>=0.5.1)"] [[package]] name = "opentelemetry-api" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Python API" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main", "dev", "proxy-dev"] files = [ - {file = "opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950"}, - {file = "opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c"}, + {file = "opentelemetry_api-1.28.0-py3-none-any.whl", hash = "sha256:8457cd2c59ea1bd0988560f021656cecd254ad7ef6be4ba09dbefeca2409ce52"}, + {file = "opentelemetry_api-1.28.0.tar.gz", hash = "sha256:578610bcb8aa5cdcb11169d136cc752958548fb6ccffb0969c1036b0ee9e5353"}, ] markers = {main = "python_version >= \"3.10\""} [package.dependencies] -importlib-metadata = ">=6.0,<8.8.0" -typing-extensions = ">=4.5.0" +deprecated = ">=1.2.6" +importlib-metadata = ">=6.0,<=8.5.0" [[package]] name = "opentelemetry-exporter-otlp" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Collector Exporters" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["dev", "proxy-dev"] files = [ - {file = "opentelemetry_exporter_otlp-1.39.1-py3-none-any.whl", hash = "sha256:68ae69775291f04f000eb4b698ff16ff685fdebe5cb52871bc4e87938a7b00fe"}, - {file = "opentelemetry_exporter_otlp-1.39.1.tar.gz", hash = "sha256:7cf7470e9fd0060c8a38a23e4f695ac686c06a48ad97f8d4867bc9b420180b9c"}, + {file = "opentelemetry_exporter_otlp-1.28.0-py3-none-any.whl", hash = "sha256:1fd02d70f2c1b7ac5579c81e78de4594b188d3317c8ceb69e8b53900fb7b40fd"}, + {file = "opentelemetry_exporter_otlp-1.28.0.tar.gz", hash = "sha256:31ae7495831681dd3da34ac457f6970f147465ae4b9aae3a888d7a581c7cd868"}, ] [package.dependencies] -opentelemetry-exporter-otlp-proto-grpc = "1.39.1" -opentelemetry-exporter-otlp-proto-http = "1.39.1" +opentelemetry-exporter-otlp-proto-grpc = "1.28.0" +opentelemetry-exporter-otlp-proto-http = "1.28.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Protobuf encoding" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["dev", "proxy-dev"] files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.28.0-py3-none-any.whl", hash = "sha256:467e6437d24e020156dffecece8c0a4471a8a60f6a34afeda7386df31a092410"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.28.0.tar.gz", hash = "sha256:5fa0419b0c8e291180b0fc8430a20dd44a3f3236f8e0827992145914f273ec4f"}, ] [package.dependencies] -opentelemetry-proto = "1.39.1" +opentelemetry-proto = "1.28.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["dev", "proxy-dev"] files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.39.1-py3-none-any.whl", hash = "sha256:fa1c136a05c7e9b4c09f739469cbdb927ea20b34088ab1d959a849b5cc589c18"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.39.1.tar.gz", hash = "sha256:772eb1c9287485d625e4dbe9c879898e5253fea111d9181140f51291b5fec3ad"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.28.0-py3-none-any.whl", hash = "sha256:edbdc53e7783f88d4535db5807cb91bd7b1ec9e9b9cdbfee14cd378f29a3b328"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.28.0.tar.gz", hash = "sha256:47a11c19dc7f4289e220108e113b7de90d59791cb4c37fc29f69a6a56f2c3735"}, ] [package.dependencies] -googleapis-common-protos = ">=1.57,<2.0" -grpcio = [ - {version = ">=1.63.2,<2.0.0", markers = "python_version < \"3.13\""}, - {version = ">=1.66.2,<2.0.0", markers = "python_version >= \"3.13\""}, -] +deprecated = ">=1.2.6" +googleapis-common-protos = ">=1.52,<2.0" +grpcio = ">=1.63.2,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.39.1" -opentelemetry-proto = "1.39.1" -opentelemetry-sdk = ">=1.39.1,<1.40.0" -typing-extensions = ">=4.6.0" - -[package.extras] -gcp-auth = ["opentelemetry-exporter-credential-provider-gcp (>=0.59b0)"] +opentelemetry-exporter-otlp-proto-common = "1.28.0" +opentelemetry-proto = "1.28.0" +opentelemetry-sdk = ">=1.28.0,<1.29.0" [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Collector Protobuf over HTTP Exporter" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["dev", "proxy-dev"] files = [ - {file = "opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985"}, - {file = "opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.28.0-py3-none-any.whl", hash = "sha256:e8f3f7961b747edb6b44d51de4901a61e9c01d50debd747b120a08c4996c7e7b"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.28.0.tar.gz", hash = "sha256:d83a9a03a8367ead577f02a64127d827c79567de91560029688dd5cfd0152a8e"}, ] [package.dependencies] +deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.39.1" -opentelemetry-proto = "1.39.1" -opentelemetry-sdk = ">=1.39.1,<1.40.0" +opentelemetry-exporter-otlp-proto-common = "1.28.0" +opentelemetry-proto = "1.28.0" +opentelemetry-sdk = ">=1.28.0,<1.29.0" requests = ">=2.7,<3.0" -typing-extensions = ">=4.5.0" - -[package.extras] -gcp-auth = ["opentelemetry-exporter-credential-provider-gcp (>=0.59b0)"] [[package]] name = "opentelemetry-proto" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Python Proto" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main", "dev", "proxy-dev"] files = [ - {file = "opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007"}, - {file = "opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8"}, + {file = "opentelemetry_proto-1.28.0-py3-none-any.whl", hash = "sha256:d5ad31b997846543b8e15504657d9a8cf1ad3c71dcbbb6c4799b1ab29e38f7f9"}, + {file = "opentelemetry_proto-1.28.0.tar.gz", hash = "sha256:4a45728dfefa33f7908b828b9b7c9f2c6de42a05d5ec7b285662ddae71c4c870"}, ] markers = {main = "python_version >= \"3.10\" and extra == \"mlflow\""} [package.dependencies] -protobuf = ">=5.0,<7.0" +protobuf = ">=5.0,<6.0" [[package]] name = "opentelemetry-sdk" -version = "1.39.1" +version = "1.28.0" description = "OpenTelemetry Python SDK" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main", "dev", "proxy-dev"] files = [ - {file = "opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c"}, - {file = "opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6"}, + {file = "opentelemetry_sdk-1.28.0-py3-none-any.whl", hash = "sha256:4b37da81d7fad67f6683c4420288c97f4ed0d988845d5886435f428ec4b8429a"}, + {file = "opentelemetry_sdk-1.28.0.tar.gz", hash = "sha256:41d5420b2e3fb7716ff4981b510d551eff1fc60eb5a95cf7335b31166812a893"}, ] markers = {main = "python_version >= \"3.10\""} [package.dependencies] -opentelemetry-api = "1.39.1" -opentelemetry-semantic-conventions = "0.60b1" -typing-extensions = ">=4.5.0" +opentelemetry-api = "1.28.0" +opentelemetry-semantic-conventions = "0.49b0" +typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.60b1" +version = "0.49b0" description = "OpenTelemetry Semantic Conventions" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main", "dev", "proxy-dev"] files = [ - {file = "opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb"}, - {file = "opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953"}, + {file = "opentelemetry_semantic_conventions-0.49b0-py3-none-any.whl", hash = "sha256:0458117f6ead0b12e3221813e3e511d85698c31901cac84682052adb9c17c7cd"}, + {file = "opentelemetry_semantic_conventions-0.49b0.tar.gz", hash = "sha256:dbc7b28339e5390b6b28e022835f9bac4e134a80ebf640848306d3c5192557e8"}, ] markers = {main = "python_version >= \"3.10\""} [package.dependencies] -opentelemetry-api = "1.39.1" -typing-extensions = ">=4.5.0" +deprecated = ">=1.2.6" +opentelemetry-api = "1.28.0" [[package]] name = "orjson" -version = "3.11.4" +version = "3.10.15" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = true -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b"}, - {file = "orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3"}, - {file = "orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc"}, - {file = "orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39"}, - {file = "orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907"}, - {file = "orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c"}, - {file = "orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a"}, - {file = "orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045"}, - {file = "orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50"}, - {file = "orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9"}, - {file = "orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa"}, - {file = "orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140"}, - {file = "orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e"}, - {file = "orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534"}, - {file = "orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6"}, - {file = "orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839"}, - {file = "orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a"}, - {file = "orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de"}, - {file = "orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803"}, - {file = "orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155"}, - {file = "orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394"}, - {file = "orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1"}, - {file = "orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d"}, - {file = "orjson-3.11.4-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:405261b0a8c62bcbd8e2931c26fdc08714faf7025f45531541e2b29e544b545b"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af02ff34059ee9199a3546f123a6ab4c86caf1708c79042caf0820dc290a6d4f"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b2eba969ea4203c177c7b38b36c69519e6067ee68c34dc37081fac74c796e10"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0baa0ea43cfa5b008a28d3c07705cf3ada40e5d347f0f44994a64b1b7b4b5350"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80fd082f5dcc0e94657c144f1b2a3a6479c44ad50be216cf0c244e567f5eae19"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e3704d35e47d5bee811fb1cbd8599f0b4009b14d451c4c57be5a7e25eb89a13"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa447f2b5356779d914658519c874cf3b7629e99e63391ed519c28c8aea4919"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bba5118143373a86f91dadb8df41d9457498226698ebdf8e11cbb54d5b0e802d"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:622463ab81d19ef3e06868b576551587de8e4d518892d1afab71e0fbc1f9cffc"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e0a700c4b82144b72946b6629968df9762552ee1344bfdb767fecdd634fbd5a"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e18a5c15e764e5f3fc569b47872450b4bcea24f2a6354c0a0e95ad21045d5a9"}, - {file = "orjson-3.11.4-cp39-cp39-win32.whl", hash = "sha256:fb1c37c71cad991ef4d89c7a634b5ffb4447dbd7ae3ae13e8f5ee7f1775e7ab1"}, - {file = "orjson-3.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:e2985ce8b8c42d00492d0ed79f2bd2b6460d00f2fa671dfde4bf2e02f49bf5c6"}, - {file = "orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d"}, + {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"}, + {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"}, + {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"}, + {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"}, + {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"}, + {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"}, + {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"}, + {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"}, + {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"}, + {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"}, + {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"}, + {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"}, + {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"}, + {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"}, + {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"}, + {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"}, + {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"}, + {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"}, + {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"}, ] [[package]] @@ -4627,19 +4833,19 @@ testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "polars" -version = "1.35.2" +version = "1.39.3" description = "Blazingly fast DataFrame library" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and extra == \"proxy\"" files = [ - {file = "polars-1.35.2-py3-none-any.whl", hash = "sha256:5e8057c8289ac148c793478323b726faea933d9776bd6b8a554b0ab7c03db87e"}, - {file = "polars-1.35.2.tar.gz", hash = "sha256:ae458b05ca6e7ca2c089342c70793f92f1103c502dc1b14b56f0a04f2cc1d205"}, + {file = "polars-1.39.3-py3-none-any.whl", hash = "sha256:c2b955ccc0a08a2bc9259785decf3d5c007b489b523bf2390cf21cec2bb82a56"}, + {file = "polars-1.39.3.tar.gz", hash = "sha256:2e016c7f3e8d14fa777ef86fe0477cec6c67023a20ba4c94d6e8431eefe4a63c"}, ] [package.dependencies] -polars-runtime-32 = "1.35.2" +polars-runtime-32 = "1.39.3" [package.extras] adbc = ["adbc-driver-manager[dbapi]", "adbc-driver-sqlite[dbapi]"] @@ -4659,11 +4865,11 @@ numpy = ["numpy (>=1.16.0)"] openpyxl = ["openpyxl (>=3.0.0)"] pandas = ["pandas", "polars[pyarrow]"] plot = ["altair (>=5.4.0)"] -polars-cloud = ["polars_cloud (>=0.0.1a1)"] +polars-cloud = ["polars_cloud (>=0.4.0)"] pyarrow = ["pyarrow (>=7.0.0)"] pydantic = ["pydantic"] -rt64 = ["polars-runtime-64 (==1.35.2)"] -rtcompat = ["polars-runtime-compat (==1.35.2)"] +rt64 = ["polars-runtime-64 (==1.39.3)"] +rtcompat = ["polars-runtime-compat (==1.39.3)"] sqlalchemy = ["polars[pandas]", "sqlalchemy"] style = ["great-tables (>=0.8.0)"] timezone = ["tzdata ; platform_system == \"Windows\""] @@ -4672,20 +4878,22 @@ xlsxwriter = ["xlsxwriter"] [[package]] name = "polars-runtime-32" -version = "1.35.2" +version = "1.39.3" description = "Blazingly fast DataFrame library" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and extra == \"proxy\"" files = [ - {file = "polars_runtime_32-1.35.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e465d12a29e8df06ea78947e50bd361cdf77535cd904fd562666a8a9374e7e3a"}, - {file = "polars_runtime_32-1.35.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef2b029b78f64fb53f126654c0bfa654045c7546bd0de3009d08bd52d660e8cc"}, - {file = "polars_runtime_32-1.35.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85dda0994b5dff7f456bb2f4bbd22be9a9e5c5e28670e23fedb13601ec99a46d"}, - {file = "polars_runtime_32-1.35.2-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:3b9006902fc51b768ff747c0f74bd4ce04005ee8aeb290ce9c07ce1cbe1b58a9"}, - {file = "polars_runtime_32-1.35.2-cp39-abi3-win_amd64.whl", hash = "sha256:ddc015fac39735592e2e7c834c02193ba4d257bb4c8c7478b9ebe440b0756b84"}, - {file = "polars_runtime_32-1.35.2-cp39-abi3-win_arm64.whl", hash = "sha256:6861145aa321a44eda7cc6694fb7751cb7aa0f21026df51b5faa52e64f9dc39b"}, - {file = "polars_runtime_32-1.35.2.tar.gz", hash = "sha256:6e6e35733ec52abe54b7d30d245e6586b027d433315d20edfb4a5d162c79fe90"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:425c0b220b573fa097b4042edff73114cc6d23432a21dfd2dc41adf329d7d2e9"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef5884711e3c617d7dc93519a7d038e242f5741cfe5fe9afd32d58845d86c562"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06b47f535eb1f97a9a1e5b0053ef50db3a4276e241178e37bbb1a38b1fa53b14"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bc9e13dc1d2e828331f2fe8ccbc9757554dc4933a8d3e85e906b988178f95ed"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:363d49e3a3e638fc943e2b9887940300a7d06789930855a178a4727949259dc2"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7c206bdcc7bc62ea038d6adea8e44b02f0e675e0191a54c810703b4895208ea4"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-win_amd64.whl", hash = "sha256:d66ca522517554a883446957539c40dc7b75eb0c2220357fb28bc8940d305339"}, + {file = "polars_runtime_32-1.39.3-cp310-abi3-win_arm64.whl", hash = "sha256:f49f51461de63f13e5dd4eb080421c8f23f856945f3f8bd5b2b1f59da52c2860"}, + {file = "polars_runtime_32-1.39.3.tar.gz", hash = "sha256:c728e4f469cafab501947585f36311b8fb222d3e934c6209e83791e0df20b29d"}, ] [[package]] @@ -4714,6 +4922,25 @@ files = [ {file = "port_for-1.0.0.tar.gz", hash = "sha256:404d161b1b2c82e2f6b31d8646396b4847d02bf5ee10068c92b7263657a14582"}, ] +[[package]] +name = "prettytable" +version = "3.17.0" +description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.10\" and extra == \"mlflow\"" +files = [ + {file = "prettytable-3.17.0-py3-none-any.whl", hash = "sha256:aad69b294ddbe3e1f95ef8886a060ed1666a0b83018bbf56295f6f226c43d287"}, + {file = "prettytable-3.17.0.tar.gz", hash = "sha256:59f2590776527f3c9e8cf9fe7b66dd215837cca96a9c39567414cbc632e8ddb0"}, +] + +[package.dependencies] +wcwidth = "*" + +[package.extras] +tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] + [[package]] name = "priority" version = "2.0.0" @@ -5118,14 +5345,14 @@ pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycodestyle" -version = "2.11.1" +version = "2.14.0" description = "Python style guide checker" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, + {file = "pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d"}, + {file = "pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783"}, ] [[package]] @@ -5139,18 +5366,18 @@ files = [ {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, ] -markers = {main = "implementation_name != \"PyPy\" and (platform_python_implementation != \"PyPy\" or extra == \"proxy\")", dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"", proxy-dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""} +markers = {main = "(platform_python_implementation != \"PyPy\" or extra == \"proxy\") and implementation_name != \"PyPy\"", dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"", proxy-dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""} [[package]] name = "pydantic" -version = "2.12.4" +version = "2.12.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" groups = ["main", "dev", "proxy-dev"] files = [ - {file = "pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e"}, - {file = "pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac"}, + {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, + {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, ] [package.dependencies] @@ -5325,14 +5552,14 @@ yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "pyflakes" -version = "3.1.0" +version = "3.4.0" description = "passive checker of Python programs" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, + {file = "pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f"}, + {file = "pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58"}, ] [[package]] @@ -5375,40 +5602,38 @@ tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] [[package]] name = "pynacl" -version = "1.6.1" +version = "1.6.2" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "pynacl-1.6.1-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:7d7c09749450c385301a3c20dca967a525152ae4608c0a096fe8464bfc3df93d"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc734c1696ffd49b40f7c1779c89ba908157c57345cf626be2e0719488a076d3"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3cd787ec1f5c155dc8ecf39b1333cfef41415dc96d392f1ce288b4fe970df489"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b35d93ab2df03ecb3aa506be0d3c73609a51449ae0855c2e89c7ed44abde40b"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dece79aecbb8f4640a1adbb81e4aa3bfb0e98e99834884a80eb3f33c7c30e708"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c2228054f04bf32d558fb89bb99f163a8197d5a9bf4efa13069a7fa8d4b93fc3"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:2b12f1b97346f177affcdfdc78875ff42637cb40dcf79484a97dae3448083a78"}, - {file = "pynacl-1.6.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e735c3a1bdfde3834503baf1a6d74d4a143920281cb724ba29fb84c9f49b9c48"}, - {file = "pynacl-1.6.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3384a454adf5d716a9fadcb5eb2e3e72cd49302d1374a60edc531c9957a9b014"}, - {file = "pynacl-1.6.1-cp314-cp314t-win32.whl", hash = "sha256:d8615ee34d01c8e0ab3f302dcdd7b32e2bcf698ba5f4809e7cc407c8cdea7717"}, - {file = "pynacl-1.6.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5f5b35c1a266f8a9ad22525049280a600b19edd1f785bccd01ae838437dcf935"}, - {file = "pynacl-1.6.1-cp314-cp314t-win_arm64.whl", hash = "sha256:d984c91fe3494793b2a1fb1e91429539c6c28e9ec8209d26d25041ec599ccf63"}, - {file = "pynacl-1.6.1-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:a6f9fd6d6639b1e81115c7f8ff16b8dedba1e8098d2756275d63d208b0e32021"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e49a3f3d0da9f79c1bec2aa013261ab9fa651c7da045d376bd306cf7c1792993"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7713f8977b5d25f54a811ec9efa2738ac592e846dd6e8a4d3f7578346a841078"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a3becafc1ee2e5ea7f9abc642f56b82dcf5be69b961e782a96ea52b55d8a9fc"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ce50d19f1566c391fedc8dc2f2f5be265ae214112ebe55315e41d1f36a7f0a9"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:543f869140f67d42b9b8d47f922552d7a967e6c116aad028c9bfc5f3f3b3a7b7"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a2bb472458c7ca959aeeff8401b8efef329b0fc44a89d3775cffe8fad3398ad8"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3206fa98737fdc66d59b8782cecc3d37d30aeec4593d1c8c145825a345bba0f0"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:53543b4f3d8acb344f75fd4d49f75e6572fce139f4bfb4815a9282296ff9f4c0"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:319de653ef84c4f04e045eb250e6101d23132372b0a61a7acf91bac0fda8e58c"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:262a8de6bba4aee8a66f5edf62c214b06647461c9b6b641f8cd0cb1e3b3196fe"}, - {file = "pynacl-1.6.1-cp38-abi3-win32.whl", hash = "sha256:9fd1a4eb03caf8a2fe27b515a998d26923adb9ddb68db78e35ca2875a3830dde"}, - {file = "pynacl-1.6.1-cp38-abi3-win_amd64.whl", hash = "sha256:a569a4069a7855f963940040f35e87d8bc084cb2d6347428d5ad20550a0a1a21"}, - {file = "pynacl-1.6.1-cp38-abi3-win_arm64.whl", hash = "sha256:5953e8b8cfadb10889a6e7bd0f53041a745d1b3d30111386a1bb37af171e6daf"}, - {file = "pynacl-1.6.1.tar.gz", hash = "sha256:8d361dac0309f2b6ad33b349a56cd163c98430d409fa503b10b70b3ad66eaa1d"}, + {file = "pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b"}, + {file = "pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2"}, + {file = "pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577"}, + {file = "pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa"}, + {file = "pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0"}, + {file = "pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c"}, + {file = "pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c"}, ] [package.dependencies] @@ -5441,7 +5666,7 @@ description = "A python implementation of GNU readline." optional = true python-versions = ">=3.8" groups = ["main"] -markers = "sys_platform == \"win32\" and extra == \"extra-proxy\" and python_version < \"3.14\"" +markers = "python_version < \"3.14\" and extra == \"extra-proxy\" and sys_platform == \"win32\"" files = [ {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, @@ -5470,14 +5695,14 @@ cffi = ">=1.6.0" [[package]] name = "pytest" -version = "7.4.4" +version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, ] [package.dependencies] @@ -5485,30 +5710,32 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.21.2" +version = "1.2.0" description = "Pytest support for asyncio" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, - {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, + {file = "pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99"}, + {file = "pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57"}, ] [package.dependencies] -pytest = ">=7.0.0" +backports-asyncio-runner = {version = ">=1.1,<2", markers = "python_version < \"3.11\""} +pytest = ">=8.2,<9" +typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""} [package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-mock" @@ -5530,38 +5757,38 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pytest-postgresql" -version = "6.1.1" +version = "7.0.2" description = "Postgresql fixtures and fixture factories for Pytest." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pytest_postgresql-6.1.1-py3-none-any.whl", hash = "sha256:bd4c0970d25685ac3d34d42263fcbfbf134bf02d22519fce7e1ccf4122d8b99a"}, - {file = "pytest_postgresql-6.1.1.tar.gz", hash = "sha256:f996637367e6aecebba1349da52eea95340bdb434c90e4b79739e62c656056e2"}, + {file = "pytest_postgresql-7.0.2-py3-none-any.whl", hash = "sha256:0b0d31c51620a9c1d6be93286af354256bc58a47c379f56f4147b22da6e81fb5"}, + {file = "pytest_postgresql-7.0.2.tar.gz", hash = "sha256:57c8d3f7d4e91d0ea8b2eac786d04f60080fa6ed6e66f1f94d747c71c9e5a4f4"}, ] [package.dependencies] -mirakuru = "*" +mirakuru = ">=2.6.0" +packaging = "*" port-for = ">=0.7.3" psycopg = ">=3.0.0" -pytest = ">=6.2" -setuptools = "*" +pytest = ">=7.2" [[package]] name = "pytest-rerunfailures" -version = "14.0" +version = "15.1" description = "pytest plugin to re-run tests to eliminate flaky failures" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pytest-rerunfailures-14.0.tar.gz", hash = "sha256:4a400bcbcd3c7a4ad151ab8afac123d90eca3abe27f98725dc4d9702887d2e92"}, - {file = "pytest_rerunfailures-14.0-py3-none-any.whl", hash = "sha256:4197bdd2eaeffdbf50b5ea6e7236f47ff0e44d1def8dae08e409f536d84e7b32"}, + {file = "pytest_rerunfailures-15.1-py3-none-any.whl", hash = "sha256:f674c3594845aba8b23c78e99b1ff8068556cc6a8b277f728071fdc4f4b0b355"}, + {file = "pytest_rerunfailures-15.1.tar.gz", hash = "sha256:c6040368abd7b8138c5b67288be17d6e5611b7368755ce0465dda0362c8ece80"}, ] [package.dependencies] packaging = ">=17.1" -pytest = ">=7.2" +pytest = ">=7.4,<8.2.2 || >8.2.2" [[package]] name = "pytest-xdist" @@ -5602,14 +5829,14 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main", "proxy-dev"] files = [ - {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, - {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, ] [package.extras] @@ -5622,25 +5849,12 @@ description = "A streaming multipart parser for Python" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "python_version == \"3.9\" and extra == \"proxy\"" +markers = "extra == \"proxy\"" files = [ {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"}, {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, ] -[[package]] -name = "python-multipart" -version = "0.0.22" -description = "A streaming multipart parser for Python" -optional = true -python-versions = ">=3.10" -groups = ["main"] -markers = "python_version >= \"3.10\" and extra == \"proxy\"" -files = [ - {file = "python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155"}, - {file = "python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58"}, -] - [[package]] name = "python-ulid" version = "3.1.0" @@ -5795,7 +6009,7 @@ files = [ {file = "redis-5.3.1-py3-none-any.whl", hash = "sha256:dc1909bd24669cc31b5f67a039700b16ec30571096c5f1f0d9d2324bff31af97"}, {file = "redis-5.3.1.tar.gz", hash = "sha256:ca49577a531ea64039b5a36db3d6cd1a0c7a60c34124d46924a45b956e8cf14c"}, ] -markers = {main = "(python_version < \"3.14\" or extra == \"proxy\") and (python_version <= \"3.13\" or extra == \"proxy\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"proxy\")"} +markers = {main = "python_version < \"3.14\" and (extra == \"proxy\" or extra == \"extra-proxy\") or extra == \"proxy\""} [package.dependencies] async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} @@ -6041,15 +6255,15 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "resend" -version = "2.19.0" +version = "2.23.0" description = "Resend Python SDK" optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"extra-proxy\"" files = [ - {file = "resend-2.19.0-py2.py3-none-any.whl", hash = "sha256:1a8b9fcacbe058876ebce757ac2542103ed7227caec10e5c58613ee58615acaa"}, - {file = "resend-2.19.0.tar.gz", hash = "sha256:b11191561cdb0ed7aa193212b7c8865bf635013c4d11bd81caf471d1b362be02"}, + {file = "resend-2.23.0-py2.py3-none-any.whl", hash = "sha256:eca6d28a1ffd36c1fc489fa83cb6b511f384792c9f07465f7c92d96c8b4d5636"}, + {file = "resend-2.23.0.tar.gz", hash = "sha256:df613827dcc40eb1c9de2e5ff600cd4081b89b206537dec8067af1a5016d23c7"}, ] [package.dependencies] @@ -6058,14 +6272,14 @@ typing-extensions = ">=4.4.0" [[package]] name = "responses" -version = "0.25.8" +version = "0.26.0" description = "A utility library for mocking out the `requests` Python library." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "responses-0.25.8-py3-none-any.whl", hash = "sha256:0c710af92def29c8352ceadff0c3fe340ace27cf5af1bbe46fb71275bcd2831c"}, - {file = "responses-0.25.8.tar.gz", hash = "sha256:9374d047a575c8f781b94454db5cab590b6029505f488d12899ddb10a4af1cf4"}, + {file = "responses-0.26.0-py3-none-any.whl", hash = "sha256:03ec4409088cd5c66b71ecbbbd27fe2c58ddfad801c66203457b3e6a04868c37"}, + {file = "responses-0.26.0.tar.gz", hash = "sha256:c7f6923e6343ef3682816ba421c006626777893cb0d5e1434f674b649bac9eb4"}, ] [package.dependencies] @@ -6093,20 +6307,21 @@ httpx = ">=0.25.0" [[package]] name = "rich" -version = "13.7.1" +version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = true -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] @@ -6278,15 +6493,15 @@ files = [ [[package]] name = "rq" -version = "2.6.0" +version = "2.7.0" description = "RQ is a simple, lightweight, library for creating background jobs, and processing them." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "rq-2.6.0-py3-none-any.whl", hash = "sha256:be5ccc0f0fc5f32da0999648340e31476368f08067f0c3fce6768d00064edbb5"}, - {file = "rq-2.6.0.tar.gz", hash = "sha256:92ad55676cda14512c4eea5782f398a102dc3af108bea197c868c4c50c5d3e81"}, + {file = "rq-2.7.0-py3-none-any.whl", hash = "sha256:4b320e95968208d2e249fa0d3d90ee309478e2d7ea60a116f8ff9aa343a4c117"}, + {file = "rq-2.7.0.tar.gz", hash = "sha256:c2156fc7249b5d43dda918c4355cfbf8d0d299a5cdd3963918e9c8daf4b1e0c0"}, ] [package.dependencies] @@ -6294,60 +6509,45 @@ click = ">=5" croniter = "*" redis = ">=3.5,<6 || >6" -[[package]] -name = "rsa" -version = "4.9.1" -description = "Pure-Python RSA implementation" -optional = false -python-versions = "<4,>=3.6" -groups = ["main", "proxy-dev"] -files = [ - {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, - {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, -] -markers = {main = "extra == \"google\" or extra == \"extra-proxy\" or python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} - -[package.dependencies] -pyasn1 = ">=0.1.3" - [[package]] name = "ruff" -version = "0.2.2" +version = "0.15.3" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, - {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, - {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, - {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, - {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, + {file = "ruff-0.15.3-py3-none-linux_armv6l.whl", hash = "sha256:f7df0fd6f889a8d8de2ddb48a9eb55150954400f2157ea15b21a2f49ecaaf988"}, + {file = "ruff-0.15.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0198b5445197d443c3bbf2cc358f4bd477fb3951e3c7f2babc13e9bb490614a8"}, + {file = "ruff-0.15.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:adf95b5be57b25fbbbc07cd68d37414bee8729e807ad0217219558027186967e"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b56dbd9cd86489ccbad96bb58fa4c958342b5510fdeb60ea13d9d3566bd845c"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6f263ce511871955d8c5401b62c7e863988ea4d0527aa0a3b1b7ecff4d4abc4"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e90fa1bed82ffede5768232b9bd23212c547ab7cd74c752007ecade1d895ee1a"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e9d53760b7061ddbe5ea9e25381332c607fc14c40bde78f8a25392a93a68d74"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec90e3b78c56c4acca4264d371dd48e29215ecb673cc2fa3c4b799b72050e491"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7ce448fd395f822e34c8f6f7dfcd84b6726340082950858f92c4daa6baf8915"}, + {file = "ruff-0.15.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14f7d763962d385f75b9b3b57fcc5661c56c20d8b1ddc9f5c881b5fa0ba499fa"}, + {file = "ruff-0.15.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b57084e3a3d65418d376c7023711c37cce023cd2fb038a76ba15ee21f3c2c2ee"}, + {file = "ruff-0.15.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d567523ff7dcf3112b0f71231d18c3506dd06943359476ee64dea0f9c8f63976"}, + {file = "ruff-0.15.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4223088d255bf31a50b6640445b39f668164d64c23e5fa403edfb1e0b11122e5"}, + {file = "ruff-0.15.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:32399ddae088970b2db6efd8d3f49981375cb828075359b6c088ed1fe63d64e1"}, + {file = "ruff-0.15.3-py3-none-win32.whl", hash = "sha256:1f1eb95ff614351e3a89a862b6d94e6c42c170e61916e1f20facd6c38477f5f3"}, + {file = "ruff-0.15.3-py3-none-win_amd64.whl", hash = "sha256:2b22dffe5f5e1e537097aa5208684f069e495f980379c4491b1cfb198a444d0c"}, + {file = "ruff-0.15.3-py3-none-win_arm64.whl", hash = "sha256:82443c14d694d4cbd9e598ede27ef5d6f08389ccad91c933be775ea2f4e66f76"}, + {file = "ruff-0.15.3.tar.gz", hash = "sha256:78757853320d8ddb9da24e614ef69a37bcbcfd477e5a6435681188d4bce4eaa1"}, ] [[package]] name = "s3transfer" -version = "0.14.0" +version = "0.16.0" description = "An Amazon S3 Transfer Manager" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456"}, - {file = "s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125"}, + {file = "s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe"}, + {file = "s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920"}, ] [package.dependencies] @@ -6522,87 +6722,6 @@ postgres = ["psycopg[binary] (>=3.1.0,<4)"] qdrant = ["qdrant-client (>=1.11.1,<2)"] vision = ["pillow (>=10.2.0,<11.0.0) ; python_version < \"3.13\"", "torch (>=2.6.0) ; python_version < \"3.13\"", "torchvision (>=0.17.0) ; python_version < \"3.13\"", "transformers (>=4.36.2) ; python_version < \"3.13\""] -[[package]] -name = "setuptools" -version = "82.0.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0"}, - {file = "setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.13.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.18.*)", "pytest-mypy"] - -[[package]] -name = "shapely" -version = "2.0.7" -description = "Manipulation and analysis of geometric objects" -optional = true -python-versions = ">=3.7" -groups = ["main"] -markers = "extra == \"google\"" -files = [ - {file = "shapely-2.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:33fb10e50b16113714ae40adccf7670379e9ccf5b7a41d0002046ba2b8f0f691"}, - {file = "shapely-2.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f44eda8bd7a4bccb0f281264b34bf3518d8c4c9a8ffe69a1a05dabf6e8461147"}, - {file = "shapely-2.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf6c50cd879831955ac47af9c907ce0310245f9d162e298703f82e1785e38c98"}, - {file = "shapely-2.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04a65d882456e13c8b417562c36324c0cd1e5915f3c18ad516bb32ee3f5fc895"}, - {file = "shapely-2.0.7-cp310-cp310-win32.whl", hash = "sha256:7e97104d28e60b69f9b6a957c4d3a2a893b27525bc1fc96b47b3ccef46726bf2"}, - {file = "shapely-2.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:35524cc8d40ee4752520819f9894b9f28ba339a42d4922e92c99b148bed3be39"}, - {file = "shapely-2.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5cf23400cb25deccf48c56a7cdda8197ae66c0e9097fcdd122ac2007e320bc34"}, - {file = "shapely-2.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8f1da01c04527f7da59ee3755d8ee112cd8967c15fab9e43bba936b81e2a013"}, - {file = "shapely-2.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f623b64bb219d62014781120f47499a7adc30cf7787e24b659e56651ceebcb0"}, - {file = "shapely-2.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6d95703efaa64aaabf278ced641b888fc23d9c6dd71f8215091afd8a26a66e3"}, - {file = "shapely-2.0.7-cp311-cp311-win32.whl", hash = "sha256:2f6e4759cf680a0f00a54234902415f2fa5fe02f6b05546c662654001f0793a2"}, - {file = "shapely-2.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:b52f3ab845d32dfd20afba86675c91919a622f4627182daec64974db9b0b4608"}, - {file = "shapely-2.0.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4c2b9859424facbafa54f4a19b625a752ff958ab49e01bc695f254f7db1835fa"}, - {file = "shapely-2.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5aed1c6764f51011d69a679fdf6b57e691371ae49ebe28c3edb5486537ffbd51"}, - {file = "shapely-2.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73c9ae8cf443187d784d57202199bf9fd2d4bb7d5521fe8926ba40db1bc33e8e"}, - {file = "shapely-2.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9469f49ff873ef566864cb3516091881f217b5d231c8164f7883990eec88b73"}, - {file = "shapely-2.0.7-cp312-cp312-win32.whl", hash = "sha256:6bca5095e86be9d4ef3cb52d56bdd66df63ff111d580855cb8546f06c3c907cd"}, - {file = "shapely-2.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:f86e2c0259fe598c4532acfcf638c1f520fa77c1275912bbc958faecbf00b108"}, - {file = "shapely-2.0.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a0c09e3e02f948631c7763b4fd3dd175bc45303a0ae04b000856dedebefe13cb"}, - {file = "shapely-2.0.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:06ff6020949b44baa8fc2e5e57e0f3d09486cd5c33b47d669f847c54136e7027"}, - {file = "shapely-2.0.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6dbf096f961ca6bec5640e22e65ccdec11e676344e8157fe7d636e7904fd36"}, - {file = "shapely-2.0.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adeddfb1e22c20548e840403e5e0b3d9dc3daf66f05fa59f1fcf5b5f664f0e98"}, - {file = "shapely-2.0.7-cp313-cp313-win32.whl", hash = "sha256:a7f04691ce1c7ed974c2f8b34a1fe4c3c5dfe33128eae886aa32d730f1ec1913"}, - {file = "shapely-2.0.7-cp313-cp313-win_amd64.whl", hash = "sha256:aaaf5f7e6cc234c1793f2a2760da464b604584fb58c6b6d7d94144fd2692d67e"}, - {file = "shapely-2.0.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19cbc8808efe87a71150e785b71d8a0e614751464e21fb679d97e274eca7bd43"}, - {file = "shapely-2.0.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc19b78cc966db195024d8011649b4e22812f805dd49264323980715ab80accc"}, - {file = "shapely-2.0.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd37d65519b3f8ed8976fa4302a2827cbb96e0a461a2e504db583b08a22f0b98"}, - {file = "shapely-2.0.7-cp37-cp37m-win32.whl", hash = "sha256:25085a30a2462cee4e850a6e3fb37431cbbe4ad51cbcc163af0cea1eaa9eb96d"}, - {file = "shapely-2.0.7-cp37-cp37m-win_amd64.whl", hash = "sha256:1a2e03277128e62f9a49a58eb7eb813fa9b343925fca5e7d631d50f4c0e8e0b8"}, - {file = "shapely-2.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e1c4f1071fe9c09af077a69b6c75f17feb473caeea0c3579b3e94834efcbdc36"}, - {file = "shapely-2.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3697bd078b4459f5a1781015854ef5ea5d824dbf95282d0b60bfad6ff83ec8dc"}, - {file = "shapely-2.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e9fed9a7d6451979d914cb6ebbb218b4b4e77c0d50da23e23d8327948662611"}, - {file = "shapely-2.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2934834c7f417aeb7cba3b0d9b4441a76ebcecf9ea6e80b455c33c7c62d96a24"}, - {file = "shapely-2.0.7-cp38-cp38-win32.whl", hash = "sha256:2e4a1749ad64bc6e7668c8f2f9479029f079991f4ae3cb9e6b25440e35a4b532"}, - {file = "shapely-2.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8ae5cb6b645ac3fba34ad84b32fbdccb2ab321facb461954925bde807a0d3b74"}, - {file = "shapely-2.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4abeb44b3b946236e4e1a1b3d2a0987fb4d8a63bfb3fdefb8a19d142b72001e5"}, - {file = "shapely-2.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd0e75d9124b73e06a42bf1615ad3d7d805f66871aa94538c3a9b7871d620013"}, - {file = "shapely-2.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7977d8a39c4cf0e06247cd2dca695ad4e020b81981d4c82152c996346cf1094b"}, - {file = "shapely-2.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0145387565fcf8f7c028b073c802956431308da933ef41d08b1693de49990d27"}, - {file = "shapely-2.0.7-cp39-cp39-win32.whl", hash = "sha256:98697c842d5c221408ba8aa573d4f49caef4831e9bc6b6e785ce38aca42d1999"}, - {file = "shapely-2.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:a3fb7fbae257e1b042f440289ee7235d03f433ea880e73e687f108d044b24db5"}, - {file = "shapely-2.0.7.tar.gz", hash = "sha256:28fe2997aab9a9dc026dc6a355d04e85841546b2a5d232ed953e3321ab958ee5"}, -] - -[package.dependencies] -numpy = ">=1.14,<3" - -[package.extras] -docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] -test = ["pytest", "pytest-cov"] - [[package]] name = "shellingham" version = "1.5.4" @@ -6628,6 +6747,29 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] +[[package]] +name = "skops" +version = "0.13.0" +description = "A set of tools, related to machine learning in production." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.10\" and extra == \"mlflow\"" +files = [ + {file = "skops-0.13.0-py3-none-any.whl", hash = "sha256:55e2cccb18c86f5916e4cfe5acf55ed7b0eecddf08a151906414c092fa5926dc"}, + {file = "skops-0.13.0.tar.gz", hash = "sha256:66949fd3c95cbb5c80270fbe40293c0fe1e46cb4a921860e42584dd9c20ebeb1"}, +] + +[package.dependencies] +numpy = ">=1.25.0" +packaging = ">=17.0" +prettytable = ">=3.9" +scikit-learn = ">=1.2" +scipy = ">=1.10.0" + +[package.extras] +rich = ["rich (>=12)"] + [[package]] name = "smmap" version = "5.0.2" @@ -7010,7 +7152,7 @@ description = "Pretty-print tabular data" optional = true python-versions = ">=3.7" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\"" +markers = "python_version < \"3.14\" and (extra == \"utils\" or extra == \"extra-proxy\") or extra == \"utils\"" files = [ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, @@ -7043,7 +7185,7 @@ description = "Retry code until it succeeds" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "(python_version < \"3.14\" or extra == \"google\") and (python_version <= \"3.13\" or extra == \"google\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"google\")" +markers = "python_version < \"3.14\" and (extra == \"google\" or extra == \"extra-proxy\") or extra == \"google\"" files = [ {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, @@ -7142,27 +7284,36 @@ blobfile = ["blobfile (>=2)"] [[package]] name = "tokenizers" -version = "0.22.1" +version = "0.22.2" description = "" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73"}, - {file = "tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390"}, - {file = "tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82"}, - {file = "tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138"}, - {file = "tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9"}, + {file = "tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c"}, + {file = "tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001"}, + {file = "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7"}, + {file = "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd"}, + {file = "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5"}, + {file = "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e"}, + {file = "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b"}, + {file = "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67"}, + {file = "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4"}, + {file = "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a"}, + {file = "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a"}, + {file = "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5"}, + {file = "tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92"}, + {file = "tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48"}, + {file = "tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc"}, + {file = "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4"}, + {file = "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c"}, + {file = "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195"}, + {file = "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5"}, + {file = "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319f659ee992222f04e58f84cbf407cfa66a65fe3a8de44e8ad2bc53e7d99012"}, + {file = "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e50f8554d504f617d9e9d6e4c2c2884a12b388a97c5c77f0bc6cf4cd032feee"}, + {file = "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a62ba2c5faa2dd175aaeed7b15abf18d20266189fb3406c5d0550dd34dd5f37"}, + {file = "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143b999bdc46d10febb15cbffb4207ddd1f410e2c755857b5a0797961bbdc113"}, + {file = "tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917"}, ] [package.dependencies] @@ -7171,7 +7322,7 @@ huggingface-hub = ">=0.16.4,<2.0" [package.extras] dev = ["tokenizers[testing]"] docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] -testing = ["black (==22.3)", "datasets", "numpy", "pytest", "pytest-asyncio", "requests", "ruff"] +testing = ["datasets", "numpy", "pytest", "pytest-asyncio", "requests", "ruff", "ty"] [[package]] name = "tomli" @@ -7363,31 +7514,15 @@ types-pyOpenSSL = "*" [[package]] name = "types-requests" -version = "2.31.0.6" -description = "Typing stubs for requests" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -markers = "python_version == \"3.9\"" -files = [ - {file = "types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0"}, - {file = "types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9"}, -] - -[package.dependencies] -types-urllib3 = "*" - -[[package]] -name = "types-requests" -version = "2.32.4.20250913" +version = "2.32.4.20260107" description = "Typing stubs for requests" optional = false python-versions = ">=3.9" groups = ["dev"] markers = "python_version >= \"3.10\"" files = [ - {file = "types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1"}, - {file = "types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d"}, + {file = "types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d"}, + {file = "types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f"}, ] [package.dependencies] @@ -7395,27 +7530,14 @@ urllib3 = ">=2" [[package]] name = "types-setuptools" -version = "80.9.0.20250822" +version = "75.8.0.20250225" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "types_setuptools-80.9.0.20250822-py3-none-any.whl", hash = "sha256:53bf881cb9d7e46ed12c76ef76c0aaf28cfe6211d3fab12e0b83620b1a8642c3"}, - {file = "types_setuptools-80.9.0.20250822.tar.gz", hash = "sha256:070ea7716968ec67a84c7f7768d9952ff24d28b65b6594797a464f1b3066f965"}, -] - -[[package]] -name = "types-urllib3" -version = "1.26.25.14" -description = "Typing stubs for urllib3" -optional = false -python-versions = "*" -groups = ["dev"] -markers = "python_version == \"3.9\"" -files = [ - {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"}, - {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"}, + {file = "types_setuptools-75.8.0.20250225-py3-none-any.whl", hash = "sha256:94c86b439cc60bcc68c1cda3fd2c301f007f8f9502f4fbb54c66cb5ce9b875af"}, + {file = "types_setuptools-75.8.0.20250225.tar.gz", hash = "sha256:6038f7e983d55792a5f90d8fdbf5d4c186026214a16bb65dd6ae83c624ae9636"}, ] [[package]] @@ -7516,15 +7638,15 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.39.0" +version = "0.33.0" description = "The lightning-fast ASGI server." optional = true -python-versions = ">=3.9" +python-versions = ">=3.8" groups = ["main"] -markers = "python_version == \"3.9\" and extra == \"proxy\"" +markers = "python_version >= \"3.10\" and (extra == \"mlflow\" or extra == \"proxy\") or extra == \"proxy\"" files = [ - {file = "uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a"}, - {file = "uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302"}, + {file = "uvicorn-0.33.0-py3-none-any.whl", hash = "sha256:2c30de4aeea83661a520abab179b24084a0019c0c1bbe137e5409f741cbde5f8"}, + {file = "uvicorn-0.33.0.tar.gz", hash = "sha256:3577119f82b7091cf4d3d4177bfda0bae4723ed92ab1439e8d779de880c9cc59"}, ] [package.dependencies] @@ -7533,28 +7655,7 @@ h11 = ">=0.8" typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] -standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "uvicorn" -version = "0.41.0" -description = "The lightning-fast ASGI server." -optional = true -python-versions = ">=3.10" -groups = ["main"] -markers = "python_version >= \"3.10\" and (extra == \"mlflow\" or extra == \"proxy\")" -files = [ - {file = "uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187"}, - {file = "uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a"}, -] - -[package.dependencies] -click = ">=7.0" -h11 = ">=0.8" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - -[package.extras] -standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.20)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "uvloop" @@ -7626,6 +7727,19 @@ files = [ docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] testing = ["coverage (>=7.6.0)", "pytest", "pytest-cov"] +[[package]] +name = "wcwidth" +version = "0.6.0" +description = "Measures the displayed width of unicode strings in a terminal" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.10\" and extra == \"mlflow\"" +files = [ + {file = "wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad"}, + {file = "wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159"}, +] + [[package]] name = "websockets" version = "15.0.1" @@ -7731,7 +7845,7 @@ version = "1.17.3" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" -groups = ["dev"] +groups = ["main", "dev", "proxy-dev"] files = [ {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, @@ -7815,6 +7929,7 @@ files = [ {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, ] +markers = {main = "python_version >= \"3.10\""} [[package]] name = "wsproto" @@ -8009,4 +8124,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "b238a24abf451e3a7ce954d2f565fb95172cedfb2f1b56d6ed985b67e23fed36" +content-hash = "07d8a22d9d55c35c9fc414d002bc6d8702e5079077f2b50737461112af0daed1" diff --git a/pyproject.toml b/pyproject.toml index 059c5e846f2..f80209d1210 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,58 +18,60 @@ Repository = "https://github.com/BerriAI/litellm" documentation = "https://docs.litellm.ai" Documentation = "https://docs.litellm.ai" +# Dependencies pinned from `pip install litellm[proxy]==1.83.0` PyPI resolution. +# Docker builds use requirements.txt (different pins). These two paths are independent. [tool.poetry.dependencies] python = ">=3.9,<4.0" -fastuuid = "0.13.5" +fastuuid = "0.14.0" httpx = "0.28.1" -openai = "2.24.0" +openai = "2.30.0" python-dotenv = "1.0.1" -tiktoken = "0.8.0" -importlib-metadata = "6.8.0" -tokenizers = "0.20.2" -click = "8.1.7" +tiktoken = "0.12.0" +importlib-metadata = "8.5.0" +tokenizers = "0.22.2" +click = "8.1.8" jinja2 = "3.1.6" -aiohttp = "3.13.3" +aiohttp = "3.13.5" pydantic = "2.12.5" -jsonschema = "4.26.0" -numpydoc = {version = "1.10.0", optional = true} # used in utils.py — not in Docker +jsonschema = "4.23.0" +numpydoc = {version = "1.8.0", optional = true} # not in Docker or PyPI proxy extra -uvicorn = {version = "0.32.1", optional = true} # Docker uses 0.31.1 (requirements.txt); pyproject keeps main's minimum +uvicorn = {version = "0.33.0", optional = true} uvloop = {version = "0.21.0", optional = true, markers="sys_platform != 'win32'"} gunicorn = {version = "23.0.0", optional = true} -fastapi = {version = "0.120.1", optional = true} +fastapi = {version = "0.124.4", optional = true} backoff = {version = "2.2.1", optional = true} -pyyaml = {version = "6.0.2", optional = true} -rq = {version = "2.7.0", optional = true} # not in Docker -orjson = {version = "3.11.7", optional = true} -apscheduler = {version = "3.10.4", optional = true} -fastapi-sso = { version = "0.19.0", optional = true } -PyJWT = { version = "2.12.0", optional = true, python = ">=3.9" } -python-multipart = { version = "0.0.22", optional = true} -cryptography = {version = "46.0.5", optional = true} +pyyaml = {version = "6.0.3", optional = true} +rq = {version = "2.7.0", optional = true} +orjson = {version = "3.10.15", optional = true} +apscheduler = {version = "3.11.2", optional = true} +fastapi-sso = { version = "0.16.0", optional = true } +PyJWT = { version = "2.12.1", optional = true, python = ">=3.9" } +python-multipart = { version = "0.0.20", optional = true} +cryptography = {version = "43.0.3", optional = true} # Docker uses 46.0.5; pyproject uses 43.0.3 for Poetry Python 3.9.0/3.9.1 compat prisma = {version = "0.11.0", optional = true} -azure-identity = {version = "1.16.1", optional = true, python = ">=3.9"} +azure-identity = {version = "1.25.3", optional = true, python = ">=3.9"} azure-keyvault-secrets = {version = "4.10.0", optional = true} azure-storage-blob = {version = "12.28.0", optional = true} -google-cloud-kms = {version = "2.24.2", optional = true} # not in Docker +google-cloud-kms = {version = "2.24.2", optional = true} # not in PyPI proxy extra google-cloud-iam = {version = "2.19.1", optional = true} google-cloud-aiplatform = {version = "1.133.0", optional = true} -resend = {version = "2.23.0", optional = true} # not in Docker +resend = {version = "2.23.0", optional = true} # not in PyPI proxy extra pynacl = {version = "1.6.2", optional = true} websockets = {version = "15.0.1", optional = true} -boto3 = { version = "1.40.76", optional = true } # Docker uses 1.40.53 (requirements.txt); pyproject keeps main's minimum +boto3 = { version = "1.42.80", optional = true } redisvl = {version = "0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"} -mcp = {version = "1.25.0", optional = true, python = ">=3.10"} +mcp = {version = "1.26.0", optional = true, python = ">=3.10"} a2a-sdk = {version = "0.3.25", optional = true, python = ">=3.10"} litellm-proxy-extras = {version = "0.4.62", optional = true} -rich = {version = "13.7.1", optional = true} +rich = {version = "13.9.4", optional = true} litellm-enterprise = {version = "0.1.35", optional = true} -diskcache = {version = "5.6.3", optional = true} # not in Docker -polars = {version = "1.31.0", optional = true, python = ">=3.10"} -semantic-router = {version = "0.1.12", optional = true, python = ">=3.9,<3.14"} # Docker uses 0.1.11 (install_auto_router.sh); pyproject keeps main's minimum -mlflow = {version = "3.9.0", optional = true, python = ">=3.10"} # not in Docker +diskcache = {version = "5.6.3", optional = true} +polars = {version = "1.39.3", optional = true, python = ">=3.10"} +semantic-router = {version = "0.1.12", optional = true, python = ">=3.9,<3.14"} +mlflow = {version = "3.9.0", optional = true, python = ">=3.10"} # not in PyPI proxy extra soundfile = {version = "0.12.1", optional = true} -pyroscope-io = {version = "0.8.16", optional = true, markers = "sys_platform != 'win32'"} # not in Docker +pyroscope-io = {version = "0.8.16", optional = true, markers = "sys_platform != 'win32'"} # grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels) grpcio = [ {version = "1.80.0", python = "<3.14", optional = true}, @@ -140,21 +142,21 @@ litellm = 'litellm:run_server' litellm-proxy = 'litellm.proxy.client.cli:cli' [tool.poetry.group.dev.dependencies] -diff-cover = "10.2.0" +diff-cover = "9.7.2" flake8 = "7.3.0" -black = "26.1.0" +black = "24.10.0" mypy = "1.19.0" -pytest = "9.0.2" +pytest = "8.3.5" pytest-mock = "3.15.1" -pytest-asyncio = "1.3.0" -pytest-postgresql = "8.0.0" +pytest-asyncio = "1.2.0" +pytest-postgresql = "7.0.2" pytest-xdist = "3.8.0" requests-mock = "1.12.1" responses = "0.26.0" respx = "0.22.0" ruff = "0.15.3" -types-requests = "2.32.4.20260107" -types-setuptools = "82.0.0.20260210" +types-requests = {version = "2.32.4.20260107", python = ">=3.10"} +types-setuptools = "75.8.0.20250225" types-redis = "4.6.0.20241004" types-PyYAML = "6.0.12.20250915" opentelemetry-api = "1.28.0" @@ -163,17 +165,17 @@ opentelemetry-exporter-otlp = "1.28.0" langfuse = "2.59.7" fastapi-offline = "1.7.6" fakeredis = "2.34.1" -pytest-rerunfailures = "16.1" +pytest-rerunfailures = "15.1" parameterized = "0.9.0" [tool.poetry.group.proxy-dev.dependencies] prisma = "0.11.0" -hypercorn = "0.18.0" +hypercorn = "0.17.3" prometheus-client = "0.20.0" opentelemetry-api = "1.28.0" opentelemetry-sdk = "1.28.0" opentelemetry-exporter-otlp = "1.28.0" -azure-identity = {version = "1.16.1", python = ">=3.9"} +azure-identity = {version = "1.25.3", python = ">=3.9"} a2a-sdk = {version = "0.3.25", python = ">=3.10"} [build-system] From 62b3769fb467c6926673b9d82250a8e7c4b84675 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 00:28:27 -0700 Subject: [PATCH 03/32] [Infra] Update poetry.lock with pinned dependencies Co-Authored-By: Claude Opus 4.6 (1M context) --- poetry.lock | 78 ----------------------------------------------------- 1 file changed, 78 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1fadf184772..ec28c73f6b1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2453,84 +2453,6 @@ googleapis-common-protos = {version = ">=1.56.0,<2.0.0", extras = ["grpc"]} grpcio = ">=1.44.0,<2.0.0" protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" -[[package]] -name = "grpcio" -version = "1.76.0" -description = "HTTP/2-based RPC framework" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "proxy-dev"] -files = [ - {file = "grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc"}, - {file = "grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde"}, - {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3"}, - {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990"}, - {file = "grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af"}, - {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2"}, - {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6"}, - {file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3"}, - {file = "grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b"}, - {file = "grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b"}, - {file = "grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a"}, - {file = "grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c"}, - {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465"}, - {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48"}, - {file = "grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da"}, - {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397"}, - {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749"}, - {file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00"}, - {file = "grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054"}, - {file = "grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d"}, - {file = "grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8"}, - {file = "grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280"}, - {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4"}, - {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11"}, - {file = "grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6"}, - {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8"}, - {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980"}, - {file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882"}, - {file = "grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958"}, - {file = "grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347"}, - {file = "grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2"}, - {file = "grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468"}, - {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3"}, - {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb"}, - {file = "grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae"}, - {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77"}, - {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03"}, - {file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42"}, - {file = "grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f"}, - {file = "grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8"}, - {file = "grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62"}, - {file = "grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd"}, - {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc"}, - {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a"}, - {file = "grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba"}, - {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09"}, - {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc"}, - {file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc"}, - {file = "grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e"}, - {file = "grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e"}, - {file = "grpcio-1.76.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:8ebe63ee5f8fa4296b1b8cfc743f870d10e902ca18afc65c68cf46fd39bb0783"}, - {file = "grpcio-1.76.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:3bf0f392c0b806905ed174dcd8bdd5e418a40d5567a05615a030a5aeddea692d"}, - {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b7604868b38c1bfd5cf72d768aedd7db41d78cb6a4a18585e33fb0f9f2363fd"}, - {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e6d1db20594d9daba22f90da738b1a0441a7427552cc6e2e3d1297aeddc00378"}, - {file = "grpcio-1.76.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d099566accf23d21037f18a2a63d323075bebace807742e4b0ac210971d4dd70"}, - {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ebea5cc3aa8ea72e04df9913492f9a96d9348db876f9dda3ad729cfedf7ac416"}, - {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0c37db8606c258e2ee0c56b78c62fc9dee0e901b5dbdcf816c2dd4ad652b8b0c"}, - {file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ebebf83299b0cb1721a8859ea98f3a77811e35dce7609c5c963b9ad90728f886"}, - {file = "grpcio-1.76.0-cp39-cp39-win32.whl", hash = "sha256:0aaa82d0813fd4c8e589fac9b65d7dd88702555f702fb10417f96e2a2a6d4c0f"}, - {file = "grpcio-1.76.0-cp39-cp39-win_amd64.whl", hash = "sha256:acab0277c40eff7143c2323190ea57b9ee5fd353d8190ee9652369fae735668a"}, - {file = "grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73"}, -] -markers = {main = "(python_version <= \"3.12\" or extra == \"google\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"google\") and python_version >= \"3.10\"", dev = "python_version >= \"3.10\"", proxy-dev = "python_version >= \"3.10\""} - -[package.dependencies] -typing-extensions = ">=4.12,<5.0" - -[package.extras] -protobuf = ["grpcio-tools (>=1.76.0)"] - [[package]] name = "grpcio" version = "1.80.0" From 7b277d36cd7113d2d114f2ab52cf21a9bef04a9b Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 09:43:33 -0700 Subject: [PATCH 04/32] [Fix] Fix test failures and Docker build from pinned dependency upgrade pytest-asyncio 1.x no longer provides an implicit event loop in sync fixtures/tests. Make async-dependent fixtures and tests async, and replace deprecated asyncio.get_event_loop() in tests. Switch Dockerfile.build_from_pip from Alpine to Debian slim since pyroscope-io 0.8.x has no musl wheels. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/build_from_pip/Dockerfile.build_from_pip | 14 ++++++-------- .../test_in_flight_requests_middleware.py | 2 +- .../router_strategy/test_base_routing_strategy.py | 7 ++++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docker/build_from_pip/Dockerfile.build_from_pip b/docker/build_from_pip/Dockerfile.build_from_pip index 6ac5f970670..f26b993cce5 100644 --- a/docker/build_from_pip/Dockerfile.build_from_pip +++ b/docker/build_from_pip/Dockerfile.build_from_pip @@ -1,16 +1,14 @@ -FROM python:3.13-alpine@sha256:bb1f2fdb1065c85468775c9d680dcd344f6442a2d1181ef7916b60a623f11d40 +FROM python:3.13-slim@sha256:739e7213785e88c0f702dcdc12c0973afcbd606dbf021a589cab77d6b00b579d WORKDIR /app ENV HOME=/home/litellm ENV PATH="${HOME}/venv/bin:$PATH" -# Install runtime dependencies -# Note: Using Python 3.13 for compatibility with ddtrace and other packages -# rust and cargo are required for building ddtrace from source -# musl-dev and libffi-dev are needed for some Python packages on Alpine -RUN apk update && \ - apk add --no-cache gcc musl-dev libffi-dev openssl openssl-dev rust cargo +# Install runtime dependencies needed for building native extensions +RUN apt-get update && \ + apt-get install -y --no-install-recommends gcc libffi-dev && \ + rm -rf /var/lib/apt/lists/* RUN python -m venv ${HOME}/venv RUN ${HOME}/venv/bin/pip install --no-cache-dir --upgrade pip==26.0.1 @@ -28,4 +26,4 @@ RUN prisma generate EXPOSE 4000/tcp ENTRYPOINT ["litellm"] -CMD ["--port", "4000"] \ No newline at end of file +CMD ["--port", "4000"] diff --git a/tests/test_litellm/proxy/middleware/test_in_flight_requests_middleware.py b/tests/test_litellm/proxy/middleware/test_in_flight_requests_middleware.py index 830bca49936..07da6f6d0e6 100644 --- a/tests/test_litellm/proxy/middleware/test_in_flight_requests_middleware.py +++ b/tests/test_litellm/proxy/middleware/test_in_flight_requests_middleware.py @@ -92,7 +92,7 @@ def test_non_http_scopes_not_counted(): mw = InFlightRequestsMiddleware(_InnerApp()) - asyncio.get_event_loop().run_until_complete( + asyncio.run( mw({"type": "lifespan"}, None, None) # type: ignore[arg-type] ) assert get_in_flight_requests() == 0 diff --git a/tests/test_litellm/router_strategy/test_base_routing_strategy.py b/tests/test_litellm/router_strategy/test_base_routing_strategy.py index 2ce144e9a99..02a6ce4be2a 100644 --- a/tests/test_litellm/router_strategy/test_base_routing_strategy.py +++ b/tests/test_litellm/router_strategy/test_base_routing_strategy.py @@ -20,7 +20,7 @@ from litellm.router_strategy.base_routing_strategy import BaseRoutingStrategy @pytest.fixture -def mock_dual_cache(): +async def mock_dual_cache(): dual_cache = MagicMock(spec=DualCache) dual_cache.in_memory_cache = MagicMock() dual_cache.redis_cache = MagicMock() @@ -47,7 +47,7 @@ def mock_dual_cache(): @pytest.fixture -def base_strategy(mock_dual_cache): +async def base_strategy(mock_dual_cache): return BaseRoutingStrategy( dual_cache=mock_dual_cache, should_batch_redis_writes=False, @@ -137,7 +137,8 @@ async def test_sync_in_memory_spend_with_redis(base_strategy, mock_dual_cache): assert len(base_strategy.in_memory_keys_to_update) == 1 -def test_cache_keys_management(base_strategy): +@pytest.mark.asyncio +async def test_cache_keys_management(base_strategy): # Test adding and getting cache keys base_strategy.add_to_in_memory_keys_to_update("key1") base_strategy.add_to_in_memory_keys_to_update("key2") From 7bd6fa850900b6676b4a1cf2c1bd3191e7859d3f Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 09:51:29 -0700 Subject: [PATCH 05/32] [Fix] Add hf-xet to authorized packages in license check hf-xet is Apache 2.0 licensed but PyPI metadata doesn't expose the license string, so the automated checker can't determine it. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/code_coverage_tests/liccheck.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/code_coverage_tests/liccheck.ini b/tests/code_coverage_tests/liccheck.ini index 65ac01123d1..20b6e06ad04 100644 --- a/tests/code_coverage_tests/liccheck.ini +++ b/tests/code_coverage_tests/liccheck.ini @@ -145,3 +145,4 @@ nodejs-wheel-binaries: >=24.12.0 # MIT license manually verified grpcio: >=1.69.0 # Apache License 2.0 jaraco.context: >=6.1.0 # Unknown license pypdf: >=6.6.2 # BSD-3-Clause license - https://github.com/py-pdf/pypdf/blob/main/LICENSE +hf-xet: >=1.4.2 # Apache 2.0 License - https://github.com/huggingface/xet-tools/blob/main/LICENSE From 0d637b1a766696f2f31488b3ab20522ae21fabb3 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 10:06:18 -0700 Subject: [PATCH 06/32] [Fix] Align requirements.txt versions with pyproject.toml after merge After merging main, pyproject.toml had updated dependency versions but requirements.txt still had the old pins. The Dockerfile builds litellm from source (using pyproject.toml) then installs deps from requirements.txt, so version mismatches cause pip resolution failures. Updated 21 packages to match: openai, fastuuid, tiktoken, importlib-metadata, tokenizers, click, jsonschema, fastapi, pyyaml, uvicorn, boto3, mcp, orjson, polars, apscheduler, fastapi-sso, pyjwt, python-multipart, azure-identity, rich, aiohttp. Co-Authored-By: Claude Opus 4.6 (1M context) --- requirements.txt | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/requirements.txt b/requirements.txt index 27112f031fb..7629b144b00 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,16 +10,16 @@ cryptography==46.0.5 #GHSA-r6ph-v2qm-q3c2 anyio==4.8.0 # openai + http req. httpx==0.28.1 -openai==2.24.0 # openai req. -fastapi==0.120.1 # server dep +openai==2.30.0 # openai req. +fastapi==0.124.4 # server dep starlette==0.49.1 # starlette fastapi dep backoff==2.2.1 # server dep -pyyaml==6.0.2 # server dep -uvicorn==0.31.1 # server dep +pyyaml==6.0.3 # server dep +uvicorn==0.33.0 # server dep gunicorn==23.0.0 # server dep -fastuuid==0.13.5 # for uuid4 +fastuuid==0.14.0 # for uuid4 uvloop==0.21.0 # uvicorn dep, gives us much better performance under load -boto3==1.40.53 # aws bedrock/sagemaker calls (has bedrock-agentcore-control, compatible with aioboto3) +boto3==1.42.80 # aws bedrock/sagemaker calls (has bedrock-agentcore-control, compatible with aioboto3) redis==5.2.1 # redis caching redisvl==0.4.1 ## redis semantic caching prisma==0.11.0 # for db @@ -30,21 +30,21 @@ google-cloud-aiplatform==1.133.0 # for vertex ai calls google-cloud-iam==2.19.1 # for GCP IAM Redis authentication google-genai==1.37.0 anthropic[vertex]==0.54.0 -mcp==1.25.0 ; python_version >= "3.10" # for MCP server +mcp==1.26.0 ; python_version >= "3.10" # for MCP server # google-generativeai removed - deprecated, replaced by google-genai (line 21) async_generator==1.10.0 # for async ollama calls langfuse==2.59.7 # for langfuse self-hosted logging prometheus_client==0.20.0 # for /metrics endpoint on proxy ddtrace==2.19.0 # for advanced DD tracing / profiling -orjson==3.11.7 # fast /embedding responses -polars==1.31.0 # for data processing -apscheduler==3.10.4 # for resetting budget in background -fastapi-sso==0.19.0 # admin UI, SSO -pyjwt[crypto]==2.12.0 ; python_version >= "3.9" -python-multipart==0.0.22 # admin UI +orjson==3.10.15 # fast /embedding responses +polars==1.39.3 # for data processing +apscheduler==3.11.2 # for resetting budget in background +fastapi-sso==0.16.0 # admin UI, SSO +pyjwt[crypto]==2.12.1 ; python_version >= "3.9" +python-multipart==0.0.20 # admin UI jaraco.context==6.1.2 azure-ai-contentsafety==1.0.0 # for azure content safety -azure-identity==1.16.1 ; python_version >= "3.9" # for azure content safety +azure-identity==1.25.3 ; python_version >= "3.9" # for azure content safety azure-keyvault==4.2.0 # for azure KMS integration azure-storage-file-datalake==12.20.0 # for azure buck storage logging opentelemetry-api==1.28.0 @@ -61,17 +61,17 @@ litellm-proxy-extras==0.4.62 # for proxy extras - e.g. prisma migrations llm-sandbox==0.3.31 # for skill execution in sandbox ### LITELLM PACKAGE DEPENDENCIES python-dotenv==1.0.1 # for env -tiktoken==0.8.0 # for calculating usage -importlib-metadata==6.8.0 # for random utils -tokenizers==0.20.2 # for calculating usage -click==8.1.7 # for proxy cli -rich==13.7.1 # for litellm proxy cli +tiktoken==0.12.0 # for calculating usage +importlib-metadata==8.5.0 # for random utils +tokenizers==0.22.2 # for calculating usage +click==8.1.8 # for proxy cli +rich==13.9.4 # for litellm proxy cli jinja2==3.1.6 # for prompt templates aioboto3==15.5.0 # for async sagemaker calls -aiohttp==3.13.3 # for network calls +aiohttp==3.13.5 # for network calls tenacity==8.5.0 # for retrying requests, when litellm.num_retries set pydantic==2.12.5 # proxy + openai req. + mcp -jsonschema==4.26.0 # validating json schema - aligned with openapi-core + mcp +jsonschema==4.23.0 # validating json schema - aligned with openapi-core + mcp websockets==15.0.1 # for realtime API soundfile==0.12.1 # for audio file processing openapi-core==0.21.0 # for OpenAPI compliance tests From 43077af3786caaa3679fcbb90536fa1eff80692e Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 11:27:44 -0700 Subject: [PATCH 07/32] [Fix] Sync CircleCI dependency pins with requirements.txt CircleCI had stale version pins (e.g. boto3==1.36.0, aioboto3==13.4.0) that conflict with requirements.txt (boto3==1.42.80, aioboto3==15.5.0), causing uv resolution failures. Updated all mismatched pins across config.yml and .circleci/requirements.txt to match requirements.txt as the source of truth. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 144 ++++++++++++++++++------------------- .circleci/requirements.txt | 10 +-- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d4943b59c9a..aec1b4cdee8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ commands: # conflicts with transitive dep pins like openai<2 and pydantic>=2.11.5) pip install "pytest-mock==3.12.0" "pytest==7.3.1" "pytest-retry==1.6.3" \ "pytest-asyncio==0.21.1" "respx==0.22.0" "hypercorn==0.17.3" \ - "pydantic==2.11.0" "mcp==1.25.0" "requests-mock>=1.12.1" \ + "pydantic==2.12.5" "mcp==1.26.0" "requests-mock>=1.12.1" \ "responses==0.25.7" "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" \ "pytest-cov==5.0.0" "semantic_router==0.1.10" "fastapi-offline==1.7.3" \ "a2a" "parameterized>=0.9.0" @@ -150,16 +150,16 @@ jobs: python -m pip install --upgrade pip python -m pip install -r .circleci/requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-asyncio==0.21.1" "pytest-cov==5.0.0" \ - "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.43.0" pyarrow \ - "boto3==1.36.0" "aioboto3==13.4.0" langchain lunary==0.2.5 \ - "azure-identity==1.16.1" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ + "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.133.0" pyarrow \ + "boto3==1.42.80" "aioboto3==15.5.0" langchain lunary==0.2.5 \ + "azure-identity==1.25.3" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ traceloop-sdk==0.21.1 openai==1.100.1 prisma==0.11.0 \ "detect_secrets==1.5.0" "respx==0.22.0" fastapi \ - "gunicorn==21.2.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ - "apscheduler==3.10.4" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ - python-multipart prometheus-client==0.20.0 "pydantic==2.10.2" \ - "diskcache==5.6.1" "Pillow==10.3.0" "jsonschema==4.22.0" \ - "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==13.1.0" + "gunicorn==23.0.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ + "apscheduler==3.11.2" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ + python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ + "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ + "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -245,16 +245,16 @@ jobs: python -m pip install --upgrade pip python -m pip install -r .circleci/requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-asyncio==0.21.1" "pytest-cov==5.0.0" \ - "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.43.0" pyarrow \ - "boto3==1.36.0" "aioboto3==13.4.0" langchain lunary==0.2.5 \ - "azure-identity==1.16.1" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ + "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.133.0" pyarrow \ + "boto3==1.42.80" "aioboto3==15.5.0" langchain lunary==0.2.5 \ + "azure-identity==1.25.3" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ traceloop-sdk==0.21.1 openai==1.100.1 prisma==0.11.0 \ "detect_secrets==1.5.0" "respx==0.22.0" fastapi \ - "gunicorn==21.2.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ - "apscheduler==3.10.4" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ - python-multipart prometheus-client==0.20.0 "pydantic==2.10.2" \ - "diskcache==5.6.1" "Pillow==10.3.0" "jsonschema==4.22.0" \ - "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==13.1.0" + "gunicorn==23.0.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ + "apscheduler==3.11.2" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ + python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ + "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ + "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -346,42 +346,42 @@ jobs: pip install "pytest-cov==5.0.0" pip install "mypy==1.18.2" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" + pip install "aioboto3==15.5.0" pip install langchain pip install lunary==0.2.5 - pip install "azure-identity==1.16.1" + pip install "azure-identity==1.25.3" pip install "langfuse==2.59.7" pip install "logfire==0.29.0" pip install numpydoc pip install traceloop-sdk==0.21.1 - pip install opentelemetry-api==1.25.0 - pip install opentelemetry-sdk==1.25.0 - pip install opentelemetry-exporter-otlp==1.25.0 + pip install opentelemetry-api==1.28.0 + pip install opentelemetry-sdk==1.28.0 + pip install opentelemetry-exporter-otlp==1.28.0 pip install openai==1.100.1 pip install prisma==0.11.0 pip install "detect_secrets==1.5.0" - pip install "httpx==0.24.1" + pip install "httpx==0.28.1" pip install "respx==0.22.0" pip install fastapi - pip install "gunicorn==21.2.0" - pip install "anyio==4.2.0" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" - pip install "apscheduler==3.10.4" + pip install "apscheduler==3.11.2" pip install "PyGithub==1.59.1" pip install argon2-cffi pip install "pytest-mock==3.12.0" pip install python-multipart pip install google-cloud-aiplatform pip install prometheus-client==0.20.0 - pip install "pydantic==2.10.2" + pip install "pydantic==2.12.5" pip install "diskcache==5.6.1" - pip install "Pillow==10.3.0" - pip install "jsonschema==4.22.0" - pip install "websockets==13.1.0" + pip install "Pillow==12.1.1" + pip install "jsonschema==4.23.0" + pip install "websockets==15.0.1" - setup_litellm_enterprise_pip - save_cache: paths: @@ -700,8 +700,8 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.11.0" - pip install "mcp==1.25.0" + pip install "pydantic==2.12.5" + pip install "mcp==1.26.0" pip install "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -746,7 +746,7 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.11.0" + pip install "pydantic==2.12.5" pip install "a2a-sdk" # Run pytest and generate JUnit XML report - run: @@ -791,8 +791,8 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.10.2" - pip install "boto3==1.36.0" + pip install "pydantic==2.12.5" + pip install "boto3==1.42.80" pip install "semantic_router==0.1.10" --no-deps pip install aurelio_sdk pip install "pytest-xdist==3.6.1" @@ -841,7 +841,7 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.10.2" + pip install "pydantic==2.12.5" # Run pytest and generate JUnit XML report - run: name: Run tests @@ -1048,8 +1048,8 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" pip install "hypercorn==0.17.3" - pip install "pydantic==2.11.0" - pip install "mcp==1.25.0" + pip install "pydantic==2.12.5" + pip install "mcp==1.26.0" pip install "requests-mock>=1.12.1" pip install "responses==0.25.7" pip install "pytest-xdist==3.6.1" @@ -1090,7 +1090,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "pytest-cov==5.0.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1137,7 +1137,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "pytest-cov==5.0.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pytest-mock pip install "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report @@ -1259,9 +1259,9 @@ jobs: pip install pytest-mock pip install "respx==0.22.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install "mlflow==2.17.2" - pip install "anthropic==0.52.0" + pip install "anthropic==0.54.0" pip install "blockbuster==1.5.24" pip install "pytest-xdist==3.6.1" pip install "pytest-timeout==2.2.0" @@ -1352,11 +1352,11 @@ jobs: pip install aiohttp pip install openai pip install click - pip install "boto3==1.36.0" + pip install "boto3==1.42.80" pip install jinja2 - pip install "tokenizers==0.20.0" + pip install "tokenizers==0.22.2" pip install "uvloop==0.21.0" - pip install "fastuuid==0.12.0" + pip install "fastuuid==0.14.0" pip install jsonschema - setup_litellm_enterprise_pip - run: @@ -1389,7 +1389,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "pytest-cov==5.0.0" pip install "tomli==2.2.1" - pip install "mcp==1.25.0" + pip install "mcp==1.26.0" - run: name: Run tests command: | @@ -1679,10 +1679,10 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "mypy==1.18.2" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" + pip install "aioboto3==15.5.0" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -1690,9 +1690,9 @@ jobs: pip install prisma pip install fastapi pip install jsonschema - pip install "httpx==0.24.1" - pip install "gunicorn==21.2.0" - pip install "anyio==3.7.1" + pip install "httpx==0.28.1" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" @@ -1823,10 +1823,10 @@ jobs: pip install "mypy==1.18.2" pip install "jsonlines==4.0.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" + pip install "aioboto3==15.5.0" pip install langchain pip install "langchain_mcp_adapters==0.0.5" pip install "langfuse>=2.0.0" @@ -1835,9 +1835,9 @@ jobs: pip install prisma pip install fastapi pip install jsonschema - pip install "httpx==0.24.1" - pip install "gunicorn==21.2.0" - pip install "anyio==3.7.1" + pip install "httpx==0.28.1" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" @@ -1969,10 +1969,10 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "mypy==1.18.2" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" + pip install "aioboto3==15.5.0" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -1980,9 +1980,9 @@ jobs: pip install prisma pip install fastapi pip install jsonschema - pip install "httpx==0.24.1" - pip install "gunicorn==21.2.0" - pip install "anyio==3.7.1" + pip install "httpx==0.28.1" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" @@ -2611,16 +2611,16 @@ jobs: pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install aiohttp pip install "openai==1.100.1" pip install "assemblyai==0.37.0" python -m pip install --upgrade pip - pip install "pydantic==2.10.2" + pip install "pydantic==2.12.5" pip install "pytest==7.3.1" pip install "pytest-mock==3.12.0" pip install "pytest-asyncio==0.21.1" - pip install "boto3==1.36.0" + pip install "boto3==1.42.80" pip install "mypy==1.18.2" pip install pyarrow pip install numpydoc @@ -2628,11 +2628,11 @@ jobs: pip install fastapi pip install jsonschema pip install "httpx==0.27.0" - pip install "anyio==3.7.1" + pip install "anyio==4.8.0" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" pip install "google-cloud-aiplatform==1.59.0" - pip install "anthropic==0.52.0" + pip install "anthropic==0.54.0" pip install "langchain_mcp_adapters==0.0.5" pip install "langchain_openai==0.2.1" pip install "langgraph==0.3.18" @@ -2799,7 +2799,7 @@ jobs: conda activate myenv pip install "pytest==7.3.1" pip install "pytest-asyncio==0.21.1" - pip install "boto3==1.36.0" + pip install "boto3==1.42.80" pip install "httpx==0.27.0" pip install "claude-agent-sdk" pip install -r requirements.txt diff --git a/.circleci/requirements.txt b/.circleci/requirements.txt index ab4c3995772..be12ab2d0f1 100644 --- a/.circleci/requirements.txt +++ b/.circleci/requirements.txt @@ -7,15 +7,15 @@ cohere redis==5.2.1 redisvl==0.4.1 anthropic -orjson==3.10.12 # fast /embedding responses -pydantic==2.11.0 -google-cloud-aiplatform==1.43.0 +orjson==3.10.15 # fast /embedding responses +pydantic==2.12.5 +google-cloud-aiplatform==1.133.0 google-cloud-iam==2.19.1 fastapi-sso==0.16.0 uvloop==0.21.0 -mcp==1.25.0 # for MCP server +mcp==1.26.0 # for MCP server semantic_router==0.1.10 # for auto-routing with litellm -fastuuid==0.12.0 +fastuuid==0.14.0 responses==0.25.7 # for proxy client tests pytest-retry==1.6.3 # for automatic test retries litellm-proxy-extras # for prisma migrations \ No newline at end of file From 467abd19090e731bd13dcd0de8e0e07e78a1820f Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 11:34:19 -0700 Subject: [PATCH 08/32] [Fix] Add uv override for boto3/aioboto3 botocore conflict boto3==1.42.80 requires botocore>=1.42.80 but aioboto3==15.5.0 (via aiobotocore==2.25.1) requires botocore<1.40.62. No aioboto3 release supports botocore 1.42.x yet. pip's lenient resolver handles this for Docker builds, but uv's strict resolver rejects it in CI. Added uv-overrides.txt to force botocore to match boto3 during uv installs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 46 ++++++++++++++++++++++---------------------- uv-overrides.txt | 6 ++++++ 2 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 uv-overrides.txt diff --git a/.circleci/config.yml b/.circleci/config.yml index aec1b4cdee8..45abef22707 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,7 +34,7 @@ commands: command: | python -m pip install --upgrade pip uv # Use uv for the heavy requirements.txt (10-100x faster than pip) - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt # Use pip for test deps (small set, avoids uv strict-resolution # conflicts with transitive dep pins like openai<2 and pydantic>=2.11.5) pip install "pytest-mock==3.12.0" "pytest==7.3.1" "pytest-retry==1.6.3" \ @@ -95,7 +95,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip uninstall fastuuid -y pip install "mypy==1.18.2" - run: @@ -421,7 +421,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -469,7 +469,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -526,7 +526,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -568,7 +568,7 @@ jobs: command: | python -m pip install --upgrade pip uv pip install wheel setuptools - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -604,7 +604,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -653,7 +653,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets" # Run pytest and generate JUnit XML report - run: @@ -694,7 +694,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -740,7 +740,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -785,7 +785,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -835,7 +835,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -884,7 +884,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -922,7 +922,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -961,7 +961,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1040,7 +1040,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest-mock==3.12.0" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -1083,7 +1083,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "respx==0.22.0" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -1129,7 +1129,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install numpydoc pip install "respx==0.22.0" pip install "pytest==7.3.1" @@ -1178,7 +1178,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1218,7 +1218,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1251,7 +1251,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1303,7 +1303,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1383,7 +1383,7 @@ jobs: command: | python -m pip install --upgrade pip uv pip install wheel setuptools - uv pip install --system -r requirements.txt + uv pip install --system --override uv-overrides.txt -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" diff --git a/uv-overrides.txt b/uv-overrides.txt new file mode 100644 index 00000000000..e5bca971775 --- /dev/null +++ b/uv-overrides.txt @@ -0,0 +1,6 @@ +# Override aiobotocore's strict botocore pin (<1.40.62) so it can coexist +# with boto3==1.42.80 (which requires botocore>=1.42.80). +# No aioboto3/aiobotocore release yet supports botocore 1.42.x. +# pip's lenient resolver handles this (Docker builds), but uv's strict +# resolver rejects it — this override bridges the gap for CI. +botocore>=1.42.80,<1.43.0 From b7849bff56dd5de05111ab7c6b6fbcd89176197d Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 11:49:25 -0700 Subject: [PATCH 09/32] [Fix] Add boto3 override alongside botocore in uv-overrides.txt aiobotocore[boto3] pins both boto3<1.40.62 and botocore<1.40.62. The previous commit only overrode botocore. Added boto3 override too. Co-Authored-By: Claude Opus 4.6 (1M context) --- uv-overrides.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uv-overrides.txt b/uv-overrides.txt index e5bca971775..9964645b478 100644 --- a/uv-overrides.txt +++ b/uv-overrides.txt @@ -1,6 +1,7 @@ -# Override aiobotocore's strict botocore pin (<1.40.62) so it can coexist -# with boto3==1.42.80 (which requires botocore>=1.42.80). -# No aioboto3/aiobotocore release yet supports botocore 1.42.x. +# Override aiobotocore's strict boto3/botocore pins (<1.40.62) so they +# can coexist with boto3==1.42.80 (which requires botocore>=1.42.80). +# No aioboto3/aiobotocore release yet supports boto3/botocore 1.42.x. # pip's lenient resolver handles this (Docker builds), but uv's strict -# resolver rejects it — this override bridges the gap for CI. +# resolver rejects it — these overrides bridge the gap for CI. +boto3>=1.42.80,<1.43.0 botocore>=1.42.80,<1.43.0 From fc8eb81549f4e5a3992f9abad91978ecdf11e43a Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 11:57:07 -0700 Subject: [PATCH 10/32] [Fix] Filter aioboto3 from resolver to fix boto3/aioboto3 conflict boto3==1.42.80 and aioboto3==15.5.0 have incompatible botocore ranges. Both uv and pip 26.0.1 reject the resolution. Fix: filter aioboto3 out of requirements.txt at install time, then install aioboto3+aiobotocore separately with --no-deps to bypass resolution. Removes uv-overrides.txt which only partially addressed the conflict. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 84 +++++++++++++++++++++++++++++--------------- uv-overrides.txt | 7 ---- 2 files changed, 56 insertions(+), 35 deletions(-) delete mode 100644 uv-overrides.txt diff --git a/.circleci/config.yml b/.circleci/config.yml index 45abef22707..d384e860528 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,7 +34,8 @@ commands: command: | python -m pip install --upgrade pip uv # Use uv for the heavy requirements.txt (10-100x faster than pip) - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" # Use pip for test deps (small set, avoids uv strict-resolution # conflicts with transitive dep pins like openai<2 and pydantic>=2.11.5) pip install "pytest-mock==3.12.0" "pytest==7.3.1" "pytest-retry==1.6.3" \ @@ -95,7 +96,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip uninstall fastuuid -y pip install "mypy==1.18.2" - run: @@ -421,7 +423,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -469,7 +472,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -526,7 +530,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -568,7 +573,8 @@ jobs: command: | python -m pip install --upgrade pip uv pip install wheel setuptools - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -604,7 +610,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -653,7 +660,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets" # Run pytest and generate JUnit XML report - run: @@ -694,7 +702,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -740,7 +749,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -785,7 +795,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -835,7 +846,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -884,7 +896,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -922,7 +935,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -961,7 +975,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1040,7 +1055,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest-mock==3.12.0" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -1083,7 +1099,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "respx==0.22.0" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -1129,7 +1146,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install numpydoc pip install "respx==0.22.0" pip install "pytest==7.3.1" @@ -1178,7 +1196,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1218,7 +1237,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1251,7 +1271,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1303,7 +1324,8 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1383,7 +1405,8 @@ jobs: command: | python -m pip install --upgrade pip uv pip install wheel setuptools - uv pip install --system --override uv-overrides.txt -r requirements.txt + grep -v '^aioboto3' requirements.txt | uv pip install --system -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -2146,7 +2169,8 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - python -m pip install -r requirements.txt + grep -v '^aioboto3' requirements.txt | python -m pip install -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" - run: name: Install dockerize command: | @@ -2258,7 +2282,8 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - python -m pip install -r requirements.txt + grep -v '^aioboto3' requirements.txt | python -m pip install -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-mock==3.12.0" @@ -2396,7 +2421,8 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - python -m pip install -r requirements.txt + grep -v '^aioboto3' requirements.txt | python -m pip install -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-mock==3.12.0" @@ -2637,7 +2663,8 @@ jobs: pip install "langchain_openai==0.2.1" pip install "langgraph==0.3.18" pip install "fastuuid==0.13.5" - pip install -r requirements.txt + grep -v '^aioboto3' requirements.txt | pip install -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" - run: name: Install dockerize command: | @@ -2802,7 +2829,8 @@ jobs: pip install "boto3==1.42.80" pip install "httpx==0.27.0" pip install "claude-agent-sdk" - pip install -r requirements.txt + grep -v '^aioboto3' requirements.txt | pip install -r - + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" - run: name: Install dockerize command: | diff --git a/uv-overrides.txt b/uv-overrides.txt deleted file mode 100644 index 9964645b478..00000000000 --- a/uv-overrides.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Override aiobotocore's strict boto3/botocore pins (<1.40.62) so they -# can coexist with boto3==1.42.80 (which requires botocore>=1.42.80). -# No aioboto3/aiobotocore release yet supports boto3/botocore 1.42.x. -# pip's lenient resolver handles this (Docker builds), but uv's strict -# resolver rejects it — these overrides bridge the gap for CI. -boto3>=1.42.80,<1.43.0 -botocore>=1.42.80,<1.43.0 From 821a634d25bf060059525aa4826e7ca1f7230231 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 12:12:12 -0700 Subject: [PATCH 11/32] [Fix] Handle boto3/aioboto3 botocore conflict across CI and Docker builds boto3==1.42.80 and aioboto3==15.5.0 have incompatible botocore version ranges. No aioboto3 release supports botocore 1.42.x yet. Both uv and pip 26.0.1 reject the resolution. Fix: filter aioboto3 out of requirements.txt at install time, then install aioboto3+aiobotocore with --no-deps to bypass resolution. Added wrapt and aioitertools to requirements.txt as pinned transitive deps of aiobotocore (skipped by --no-deps). Fixed pip stdin handling (/dev/stdin). Applied to all 5 Dockerfiles and all CircleCI install paths. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 24 +++++++++++++----------- Dockerfile | 9 +++++++-- docker/Dockerfile.alpine | 9 +++++++-- docker/Dockerfile.database | 9 +++++++-- docker/Dockerfile.dev | 9 +++++++-- docker/Dockerfile.non_root | 8 ++++++-- requirements.txt | 2 ++ 7 files changed, 49 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d384e860528..739da356a7d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -153,7 +153,7 @@ jobs: python -m pip install -r .circleci/requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-asyncio==0.21.1" "pytest-cov==5.0.0" \ "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.133.0" pyarrow \ - "boto3==1.42.80" "aioboto3==15.5.0" langchain lunary==0.2.5 \ + "boto3==1.42.80" langchain lunary==0.2.5 \ "azure-identity==1.25.3" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ traceloop-sdk==0.21.1 openai==1.100.1 prisma==0.11.0 \ "detect_secrets==1.5.0" "respx==0.22.0" fastapi \ @@ -162,6 +162,7 @@ jobs: python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -248,7 +249,7 @@ jobs: python -m pip install -r .circleci/requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-asyncio==0.21.1" "pytest-cov==5.0.0" \ "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.133.0" pyarrow \ - "boto3==1.42.80" "aioboto3==15.5.0" langchain lunary==0.2.5 \ + "boto3==1.42.80" langchain lunary==0.2.5 \ "azure-identity==1.25.3" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ traceloop-sdk==0.21.1 openai==1.100.1 prisma==0.11.0 \ "detect_secrets==1.5.0" "respx==0.22.0" fastapi \ @@ -257,6 +258,7 @@ jobs: python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -351,7 +353,7 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install "aioboto3==15.5.0" + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install lunary==0.2.5 pip install "azure-identity==1.25.3" @@ -1705,7 +1707,7 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install "aioboto3==15.5.0" + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -1849,7 +1851,7 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install "aioboto3==15.5.0" + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install "langchain_mcp_adapters==0.0.5" pip install "langfuse>=2.0.0" @@ -1995,7 +1997,7 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install "aioboto3==15.5.0" + pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -2169,7 +2171,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - grep -v '^aioboto3' requirements.txt | python -m pip install -r - + grep -v '^aioboto3' requirements.txt | python -m pip install -r /dev/stdin pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" - run: name: Install dockerize @@ -2282,7 +2284,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - grep -v '^aioboto3' requirements.txt | python -m pip install -r - + grep -v '^aioboto3' requirements.txt | python -m pip install -r /dev/stdin pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -2421,7 +2423,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - grep -v '^aioboto3' requirements.txt | python -m pip install -r - + grep -v '^aioboto3' requirements.txt | python -m pip install -r /dev/stdin pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -2663,7 +2665,7 @@ jobs: pip install "langchain_openai==0.2.1" pip install "langgraph==0.3.18" pip install "fastuuid==0.13.5" - grep -v '^aioboto3' requirements.txt | pip install -r - + grep -v '^aioboto3' requirements.txt | pip install -r /dev/stdin pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" - run: name: Install dockerize @@ -2829,7 +2831,7 @@ jobs: pip install "boto3==1.42.80" pip install "httpx==0.27.0" pip install "claude-agent-sdk" - grep -v '^aioboto3' requirements.txt | pip install -r - + grep -v '^aioboto3' requirements.txt | pip install -r /dev/stdin pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" - run: name: Install dockerize diff --git a/Dockerfile b/Dockerfile index 07481f2b0e1..e6b3334a122 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,7 +34,10 @@ RUN ls -1 dist/*.whl | head -1 RUN pip install dist/*.whl # install dependencies as wheels -RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt +# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x +# Install them separately with --no-deps to bypass resolution +RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ + && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" # ensure pyjwt is used, not jwt RUN pip uninstall jwt -y @@ -90,7 +93,9 @@ COPY --from=builder /app/dist/*.whl . COPY --from=builder /wheels/ /wheels/ # Install the built wheel using pip; again using a wildcard if it's the only file -RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ && rm -f *.whl && rm -rf /wheels +# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid +# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) +RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && rm -f *.whl && rm -rf /wheels # Replace the nodejs-wheel-binaries bundled node with the system node (fixes CVE-2025-55130) RUN NODEJS_WHEEL_NODE=$(find /usr/lib -path "*/nodejs_wheel/bin/node" 2>/dev/null) && \ diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index 1eed9d067f1..256530a09fe 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -29,7 +29,10 @@ RUN ls -1 dist/*.whl | head -1 RUN pip install dist/*.whl # install dependencies as wheels -RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt +# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x +# Install them separately with --no-deps to bypass resolution +RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ + && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" # Runtime stage FROM $LITELLM_RUNTIME_IMAGE AS runtime @@ -44,7 +47,9 @@ COPY --from=builder /app/dist/*.whl . COPY --from=builder /wheels/ /wheels/ # Install the built wheel using pip; again using a wildcard if it's the only file -RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ && rm -f *.whl && rm -rf /wheels +# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid +# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) +RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && rm -f *.whl && rm -rf /wheels # Convert Windows line endings to Unix for entrypoint scripts RUN sed -i 's/\r$//' docker/entrypoint.sh && chmod +x docker/entrypoint.sh diff --git a/docker/Dockerfile.database b/docker/Dockerfile.database index 0d3b225aac4..1ac9ea61c74 100644 --- a/docker/Dockerfile.database +++ b/docker/Dockerfile.database @@ -40,7 +40,10 @@ RUN ls -1 dist/*.whl | head -1 RUN pip install dist/*.whl # install dependencies as wheels -RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt +# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x +# Install them separately with --no-deps to bypass resolution +RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ + && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" # Runtime stage FROM $LITELLM_RUNTIME_IMAGE AS runtime @@ -82,7 +85,9 @@ COPY --from=builder /app/dist/*.whl . COPY --from=builder /wheels/ /wheels/ # Install the built wheel using pip; again using a wildcard if it's the only file -RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ && rm -f *.whl && rm -rf /wheels +# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid +# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) +RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && rm -f *.whl && rm -rf /wheels # SECURITY FIX: nodejs-wheel-binaries (pip package used by Prisma) bundles a complete # npm with old vulnerable deps at /usr/lib/python3.*/site-packages/nodejs_wheel/. diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index 8baef56bbd3..846de3d9623 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -25,8 +25,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY requirements.txt . # Install Python dependencies with cache mount for faster rebuilds +# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x +# Install them separately with --no-deps to bypass resolution RUN --mount=type=cache,target=/root/.cache/pip \ - pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt + grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ + && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" # Fix JWT dependency conflicts early RUN pip uninstall jwt -y || true && \ @@ -109,7 +112,9 @@ COPY --from=builder /wheels/ /wheels/ COPY --from=builder /app/dist/*.whl . # Install all dependencies in one step with no-cache for smaller image -RUN pip install --no-cache-dir *.whl /wheels/* --no-index --find-links=/wheels/ && \ +# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid +# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) +RUN pip install --no-cache-dir *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && \ rm -f *.whl && \ rm -rf /wheels diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index 18c7d2fee67..2c704e09690 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -31,7 +31,10 @@ RUN for i in 1 2 3; do \ # Cache Python dependencies COPY requirements.txt . -RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt \ +# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x +# Install them separately with --no-deps to bypass resolution +RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ + && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" \ && pip wheel --no-cache-dir --wheel-dir=/wheels/ "semantic_router==0.1.11" "aurelio-sdk==0.0.19" "PyJWT==2.12.0" # Copy source after dependency layers @@ -162,7 +165,8 @@ ENV PRISMA_BINARY_CACHE_DIR=/app/.cache/prisma-python/binaries \ XDG_CACHE_HOME=/app/.cache # Install packages from wheels and optional extras without network -RUN pip install --no-index --find-links=/wheels/ -r requirements.txt && \ +RUN grep -v '^aioboto3' requirements.txt | pip install --no-index --find-links=/wheels/ -r /dev/stdin && \ + pip install --no-index --no-deps --find-links=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" && \ pip install --no-index --find-links=/wheels/ /wheels/litellm-*-py3-none-any.whl && \ pip install --no-index --find-links=/wheels/ --no-deps semantic_router==0.1.11 && \ pip install --no-index --find-links=/wheels/ aurelio-sdk==0.0.19 && \ diff --git a/requirements.txt b/requirements.txt index 7629b144b00..abac8966129 100644 --- a/requirements.txt +++ b/requirements.txt @@ -79,10 +79,12 @@ pypdf==6.9.2 # for PDF text extraction in RAG ingestion (CVE-2026-27888) # Transitive deps pinned to prevent floating between builds aiofiles==24.1.0 # transitive dep (langfuse) +aioitertools==0.12.0 # transitive dep (aiobotocore) colorlog==6.10.1 # transitive dep (ddtrace) grpc-google-iam-v1==0.14.3 # transitive dep (google-cloud-iam) hf-xet==1.4.2 # transitive dep (huggingface_hub) requests-toolbelt==1.0.0 # transitive dep (langfuse) +wrapt==1.17.2 # transitive dep (aiobotocore) ######################## # LITELLM ENTERPRISE DEPENDENCIES From 9c6d5f2b605a0a6c4d23771668234f304571918c Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 13:01:10 -0700 Subject: [PATCH 12/32] [Fix] Add aioitertools and wrapt to authorized licenses Both are transitive deps of aiobotocore, added to requirements.txt in the previous commit. aioitertools is MIT, wrapt is BSD. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/code_coverage_tests/liccheck.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/code_coverage_tests/liccheck.ini b/tests/code_coverage_tests/liccheck.ini index 20b6e06ad04..f371db6a29c 100644 --- a/tests/code_coverage_tests/liccheck.ini +++ b/tests/code_coverage_tests/liccheck.ini @@ -146,3 +146,5 @@ grpcio: >=1.69.0 # Apache License 2.0 jaraco.context: >=6.1.0 # Unknown license pypdf: >=6.6.2 # BSD-3-Clause license - https://github.com/py-pdf/pypdf/blob/main/LICENSE hf-xet: >=1.4.2 # Apache 2.0 License - https://github.com/huggingface/xet-tools/blob/main/LICENSE +aioitertools: >=0.12.0 # MIT License - https://github.com/omnilib/aioitertools/blob/main/LICENSE +wrapt: >=1.17.0 # BSD License - https://github.com/GrahamDumpleton/wrapt/blob/develop/LICENSE From 85f72c9d2457af8f1e0dc4aae058fad7f7d7884e Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 14:25:44 -0700 Subject: [PATCH 13/32] [Fix] Remove unused aioboto3 dependency and botocore conflict workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aioboto3 was listed as a dependency for async sagemaker calls but is not imported anywhere in the codebase — async calls use httpx + botocore SigV4 instead. Removing it eliminates the unresolvable botocore version conflict between boto3 and aiobotocore, along with all grep -v / --no-deps workarounds across Dockerfiles and CI. Also addresses Greptile review feedback: collapse redundant grpcio python-version markers, bump pyproject.toml cryptography to 46.0.5 to match Docker (GHSA-r6ph-v2qm-q3c2), and fix misleading .npmrc comment. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 90 ++++++++------------------ Dockerfile | 7 +- docker/Dockerfile.alpine | 7 +- docker/Dockerfile.database | 7 +- docker/Dockerfile.dev | 7 +- docker/Dockerfile.non_root | 12 ++-- pyproject.toml | 7 +- requirements.txt | 8 +-- tests/code_coverage_tests/liccheck.ini | 3 - 9 files changed, 40 insertions(+), 108 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 739da356a7d..5bbabad9107 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,8 +34,7 @@ commands: command: | python -m pip install --upgrade pip uv # Use uv for the heavy requirements.txt (10-100x faster than pip) - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt # Use pip for test deps (small set, avoids uv strict-resolution # conflicts with transitive dep pins like openai<2 and pydantic>=2.11.5) pip install "pytest-mock==3.12.0" "pytest==7.3.1" "pytest-retry==1.6.3" \ @@ -96,8 +95,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip uninstall fastuuid -y pip install "mypy==1.18.2" - run: @@ -162,7 +160,6 @@ jobs: python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -258,7 +255,6 @@ jobs: python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -353,7 +349,6 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install lunary==0.2.5 pip install "azure-identity==1.25.3" @@ -425,8 +420,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -474,8 +468,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -532,8 +525,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -575,8 +567,7 @@ jobs: command: | python -m pip install --upgrade pip uv pip install wheel setuptools - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "respx==0.22.0" pip install "pytest-retry==1.6.3" @@ -612,8 +603,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -662,8 +652,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets" # Run pytest and generate JUnit XML report - run: @@ -704,8 +693,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -751,8 +739,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -797,8 +784,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -848,8 +834,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -898,8 +883,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -937,8 +921,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -977,8 +960,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1057,8 +1039,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest-mock==3.12.0" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -1101,8 +1082,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "respx==0.22.0" pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" @@ -1148,8 +1128,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install numpydoc pip install "respx==0.22.0" pip install "pytest==7.3.1" @@ -1198,8 +1177,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-cov==5.0.0" "pytest-asyncio==0.21.1" "respx==0.22.0" "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1239,8 +1217,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1273,8 +1250,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1326,8 +1302,7 @@ jobs: name: Install Dependencies command: | python -m pip install --upgrade pip uv - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-cov==5.0.0" @@ -1407,8 +1382,7 @@ jobs: command: | python -m pip install --upgrade pip uv pip install wheel setuptools - grep -v '^aioboto3' requirements.txt | uv pip install --system -r - - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + uv pip install --system -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" @@ -1707,7 +1681,6 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -1851,7 +1824,6 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install "langchain_mcp_adapters==0.0.5" pip install "langfuse>=2.0.0" @@ -1997,7 +1969,6 @@ jobs: pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow pip install "boto3==1.42.80" - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -2171,8 +2142,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - grep -v '^aioboto3' requirements.txt | python -m pip install -r /dev/stdin - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + python -m pip install -r requirements.txt - run: name: Install dockerize command: | @@ -2284,8 +2254,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - grep -v '^aioboto3' requirements.txt | python -m pip install -r /dev/stdin - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + python -m pip install -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-mock==3.12.0" @@ -2423,8 +2392,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install aiohttp python -m pip install --upgrade pip - grep -v '^aioboto3' requirements.txt | python -m pip install -r /dev/stdin - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + python -m pip install -r requirements.txt pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-mock==3.12.0" @@ -2665,8 +2633,7 @@ jobs: pip install "langchain_openai==0.2.1" pip install "langgraph==0.3.18" pip install "fastuuid==0.13.5" - grep -v '^aioboto3' requirements.txt | pip install -r /dev/stdin - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + pip install -r requirements.txt - run: name: Install dockerize command: | @@ -2831,8 +2798,7 @@ jobs: pip install "boto3==1.42.80" pip install "httpx==0.27.0" pip install "claude-agent-sdk" - grep -v '^aioboto3' requirements.txt | pip install -r /dev/stdin - pip install --no-deps "aioboto3==15.5.0" "aiobotocore==2.25.1" + pip install -r requirements.txt - run: name: Install dockerize command: | diff --git a/Dockerfile b/Dockerfile index e6b3334a122..f4cb501ad8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,10 +34,7 @@ RUN ls -1 dist/*.whl | head -1 RUN pip install dist/*.whl # install dependencies as wheels -# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x -# Install them separately with --no-deps to bypass resolution -RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ - && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" +RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt # ensure pyjwt is used, not jwt RUN pip uninstall jwt -y @@ -93,8 +90,6 @@ COPY --from=builder /app/dist/*.whl . COPY --from=builder /wheels/ /wheels/ # Install the built wheel using pip; again using a wildcard if it's the only file -# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid -# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && rm -f *.whl && rm -rf /wheels # Replace the nodejs-wheel-binaries bundled node with the system node (fixes CVE-2025-55130) diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index 256530a09fe..bbc1ef4562b 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -29,10 +29,7 @@ RUN ls -1 dist/*.whl | head -1 RUN pip install dist/*.whl # install dependencies as wheels -# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x -# Install them separately with --no-deps to bypass resolution -RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ - && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" +RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt # Runtime stage FROM $LITELLM_RUNTIME_IMAGE AS runtime @@ -47,8 +44,6 @@ COPY --from=builder /app/dist/*.whl . COPY --from=builder /wheels/ /wheels/ # Install the built wheel using pip; again using a wildcard if it's the only file -# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid -# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && rm -f *.whl && rm -rf /wheels # Convert Windows line endings to Unix for entrypoint scripts diff --git a/docker/Dockerfile.database b/docker/Dockerfile.database index 1ac9ea61c74..36dd5a78741 100644 --- a/docker/Dockerfile.database +++ b/docker/Dockerfile.database @@ -40,10 +40,7 @@ RUN ls -1 dist/*.whl | head -1 RUN pip install dist/*.whl # install dependencies as wheels -# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x -# Install them separately with --no-deps to bypass resolution -RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ - && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" +RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt # Runtime stage FROM $LITELLM_RUNTIME_IMAGE AS runtime @@ -85,8 +82,6 @@ COPY --from=builder /app/dist/*.whl . COPY --from=builder /wheels/ /wheels/ # Install the built wheel using pip; again using a wildcard if it's the only file -# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid -# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && rm -f *.whl && rm -rf /wheels # SECURITY FIX: nodejs-wheel-binaries (pip package used by Prisma) bundles a complete diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index 846de3d9623..e0ecff31ca4 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -25,11 +25,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY requirements.txt . # Install Python dependencies with cache mount for faster rebuilds -# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x -# Install them separately with --no-deps to bypass resolution RUN --mount=type=cache,target=/root/.cache/pip \ - grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ - && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" + pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt # Fix JWT dependency conflicts early RUN pip uninstall jwt -y || true && \ @@ -112,8 +109,6 @@ COPY --from=builder /wheels/ /wheels/ COPY --from=builder /app/dist/*.whl . # Install all dependencies in one step with no-cache for smaller image -# --no-deps: all wheels are pre-built in /wheels/, skip resolution to avoid -# the boto3/aiobotocore botocore version conflict (no compatible aioboto3 exists yet) RUN pip install --no-cache-dir *.whl /wheels/* --no-index --find-links=/wheels/ --no-deps && \ rm -f *.whl && \ rm -rf /wheels diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index 2c704e09690..1cf6c0dfd15 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -31,10 +31,7 @@ RUN for i in 1 2 3; do \ # Cache Python dependencies COPY requirements.txt . -# aioboto3/aiobotocore have an unresolvable botocore conflict with boto3 1.42.x -# Install them separately with --no-deps to bypass resolution -RUN grep -v '^aioboto3' requirements.txt | pip wheel --no-cache-dir --wheel-dir=/wheels/ -r /dev/stdin \ - && pip wheel --no-cache-dir --no-deps --wheel-dir=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" \ +RUN pip wheel --no-cache-dir --wheel-dir=/wheels/ -r requirements.txt \ && pip wheel --no-cache-dir --wheel-dir=/wheels/ "semantic_router==0.1.11" "aurelio-sdk==0.0.19" "PyJWT==2.12.0" # Copy source after dependency layers @@ -44,8 +41,8 @@ COPY . . ENV LITELLM_NON_ROOT=true # Build Admin UI using the upstream command order while keeping a single RUN layer -# NOTE: --userconfig /dev/null bypasses .npmrc (which has ignore-scripts=true and -# min-release-age=3d) for this step only. This is safe because npm ci installs from +# NOTE: .npmrc (which has ignore-scripts=true and min-release-age=3d) is temporarily +# renamed during npm install/ci. This is safe because npm ci installs from # package-lock.json with pinned versions + integrity hashes. RUN mkdir -p /var/lib/litellm/ui && \ mv /app/.npmrc /app/.npmrc.bak && \ @@ -165,8 +162,7 @@ ENV PRISMA_BINARY_CACHE_DIR=/app/.cache/prisma-python/binaries \ XDG_CACHE_HOME=/app/.cache # Install packages from wheels and optional extras without network -RUN grep -v '^aioboto3' requirements.txt | pip install --no-index --find-links=/wheels/ -r /dev/stdin && \ - pip install --no-index --no-deps --find-links=/wheels/ "aioboto3==15.5.0" "aiobotocore==2.25.1" && \ +RUN pip install --no-index --find-links=/wheels/ -r requirements.txt && \ pip install --no-index --find-links=/wheels/ /wheels/litellm-*-py3-none-any.whl && \ pip install --no-index --find-links=/wheels/ --no-deps semantic_router==0.1.11 && \ pip install --no-index --find-links=/wheels/ aurelio-sdk==0.0.19 && \ diff --git a/pyproject.toml b/pyproject.toml index bba7cb4aa7c..dab869b3434 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ apscheduler = {version = "3.11.2", optional = true} fastapi-sso = { version = "0.16.0", optional = true } PyJWT = { version = "2.12.1", optional = true, python = ">=3.9" } python-multipart = { version = "0.0.20", optional = true} -cryptography = {version = "43.0.3", optional = true} # Docker uses 46.0.5; pyproject uses 43.0.3 for Poetry Python 3.9.0/3.9.1 compat +cryptography = {version = "46.0.5", optional = true} # GHSA-r6ph-v2qm-q3c2 prisma = {version = "0.11.0", optional = true} azure-identity = {version = "1.25.3", optional = true, python = ">=3.9"} azure-keyvault-secrets = {version = "4.10.0", optional = true} @@ -73,10 +73,7 @@ mlflow = {version = "3.9.0", optional = true, python = ">=3.10"} # not in PyPI p soundfile = {version = "0.12.1", optional = true} pyroscope-io = {version = "0.8.16", optional = true, markers = "sys_platform != 'win32'"} # grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels) -grpcio = [ - {version = "1.80.0", python = "<3.14", optional = true}, - {version = "1.80.0", python = ">=3.14", optional = true}, -] +grpcio = {version = "1.80.0", optional = true} [tool.poetry.extras] proxy = [ diff --git a/requirements.txt b/requirements.txt index abac8966129..ab8d6bcd918 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ uvicorn==0.33.0 # server dep gunicorn==23.0.0 # server dep fastuuid==0.14.0 # for uuid4 uvloop==0.21.0 # uvicorn dep, gives us much better performance under load -boto3==1.42.80 # aws bedrock/sagemaker calls (has bedrock-agentcore-control, compatible with aioboto3) +boto3==1.42.80 # aws bedrock/sagemaker calls redis==5.2.1 # redis caching redisvl==0.4.1 ## redis semantic caching prisma==0.11.0 # for db @@ -52,8 +52,7 @@ opentelemetry-sdk==1.28.0 opentelemetry-exporter-otlp==1.28.0 a2a-sdk==0.3.25 ; python_version >= "3.10" # grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels) -grpcio==1.80.0; python_version < "3.14" -grpcio==1.80.0; python_version >= "3.14" +grpcio==1.80.0 sentry_sdk==2.21.0 # for sentry error handling detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests tzdata==2025.1 # IANA time zone database @@ -67,7 +66,6 @@ tokenizers==0.22.2 # for calculating usage click==8.1.8 # for proxy cli rich==13.9.4 # for litellm proxy cli jinja2==3.1.6 # for prompt templates -aioboto3==15.5.0 # for async sagemaker calls aiohttp==3.13.5 # for network calls tenacity==8.5.0 # for retrying requests, when litellm.num_retries set pydantic==2.12.5 # proxy + openai req. + mcp @@ -79,12 +77,10 @@ pypdf==6.9.2 # for PDF text extraction in RAG ingestion (CVE-2026-27888) # Transitive deps pinned to prevent floating between builds aiofiles==24.1.0 # transitive dep (langfuse) -aioitertools==0.12.0 # transitive dep (aiobotocore) colorlog==6.10.1 # transitive dep (ddtrace) grpc-google-iam-v1==0.14.3 # transitive dep (google-cloud-iam) hf-xet==1.4.2 # transitive dep (huggingface_hub) requests-toolbelt==1.0.0 # transitive dep (langfuse) -wrapt==1.17.2 # transitive dep (aiobotocore) ######################## # LITELLM ENTERPRISE DEPENDENCIES diff --git a/tests/code_coverage_tests/liccheck.ini b/tests/code_coverage_tests/liccheck.ini index f371db6a29c..7657219f034 100644 --- a/tests/code_coverage_tests/liccheck.ini +++ b/tests/code_coverage_tests/liccheck.ini @@ -131,7 +131,6 @@ tiktoken: >=0.8.0 # Unknown license click: >=8.1.7 # Unknown license rich: >=13.7.1 # Unknown license aiohttp: >=3.10.2 # Unknown license -aioboto3: >=12.3.0 # Unknown license tenacity: >=8.2.3 # Unknown license pydantic: >=2.10.2 # Unknown license jsonschema: >=4.22.0 # Unknown license @@ -146,5 +145,3 @@ grpcio: >=1.69.0 # Apache License 2.0 jaraco.context: >=6.1.0 # Unknown license pypdf: >=6.6.2 # BSD-3-Clause license - https://github.com/py-pdf/pypdf/blob/main/LICENSE hf-xet: >=1.4.2 # Apache 2.0 License - https://github.com/huggingface/xet-tools/blob/main/LICENSE -aioitertools: >=0.12.0 # MIT License - https://github.com/omnilib/aioitertools/blob/main/LICENSE -wrapt: >=1.17.0 # BSD License - https://github.com/GrahamDumpleton/wrapt/blob/develop/LICENSE From 0fb5ab515dfbd0bf798aa5e55e3a3e7a02dd8739 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 14:27:51 -0700 Subject: [PATCH 14/32] [Fix] Revert cryptography to 43.0.3 in pyproject.toml for Python 3.9.0/3.9.1 compat cryptography 46.0.5 excludes Python 3.9.0 and 3.9.1, which conflicts with pyproject.toml's python = ">=3.9,<4.0" range. Docker still uses 46.0.5 via requirements.txt. Co-Authored-By: Claude Opus 4.6 (1M context) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dab869b3434..65d37804aca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ apscheduler = {version = "3.11.2", optional = true} fastapi-sso = { version = "0.16.0", optional = true } PyJWT = { version = "2.12.1", optional = true, python = ">=3.9" } python-multipart = { version = "0.0.20", optional = true} -cryptography = {version = "46.0.5", optional = true} # GHSA-r6ph-v2qm-q3c2 +cryptography = {version = "43.0.3", optional = true} # Docker uses 46.0.5; pyproject uses 43.0.3 for Poetry Python 3.9.0/3.9.1 compat prisma = {version = "0.11.0", optional = true} azure-identity = {version = "1.25.3", optional = true, python = ">=3.9"} azure-keyvault-secrets = {version = "4.10.0", optional = true} From d038093562bb0c251f9b21596c09e5303bfb768e Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 14:28:15 -0700 Subject: [PATCH 15/32] add poetry lock --- poetry.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/poetry.lock b/poetry.lock index ab22ae5d941..4798b6122d5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -40,7 +40,7 @@ description = "File support for asyncio." optional = true python-versions = ">=3.8" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"semantic-router\"" +markers = "python_version <= \"3.13\" and extra == \"semantic-router\"" files = [ {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, @@ -359,7 +359,7 @@ description = "Aurelio Platform SDK" optional = true python-versions = "<4.0,>=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"semantic-router\"" +markers = "python_version <= \"3.13\" and extra == \"semantic-router\"" files = [ {file = "aurelio_sdk-0.0.19-py3-none-any.whl", hash = "sha256:390c0212b59ce99116df8722d3badced88c5ef0bb742a6222d479ceed0ed3948"}, {file = "aurelio_sdk-0.0.19.tar.gz", hash = "sha256:14107e7440ff2efd0b4a08c52fb595e7680bd4bc973a0ddfb3b64157c6666b91"}, @@ -907,7 +907,7 @@ description = "Colored terminal output for Python's logging module" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\"" +markers = "python_version <= \"3.13\" and extra == \"extra-proxy\"" files = [ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, @@ -926,7 +926,7 @@ description = "Add colours to the output of Python's logging module." optional = true python-versions = ">=3.6" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"semantic-router\"" +markers = "python_version <= \"3.13\" and extra == \"semantic-router\"" files = [ {file = "colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c"}, {file = "colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321"}, @@ -2146,7 +2146,7 @@ files = [ {file = "google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c"}, {file = "google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8"}, ] -markers = {main = "(python_version >= \"3.10\" or extra == \"google\" or extra == \"extra-proxy\") and python_version < \"3.14\"", proxy-dev = "python_version >= \"3.10\" and python_version < \"3.14\""} +markers = {main = "(python_version >= \"3.10\" or extra == \"google\" or extra == \"extra-proxy\") and python_version <= \"3.13\"", proxy-dev = "python_version >= \"3.10\" and python_version <= \"3.13\""} [package.dependencies] google-auth = ">=2.14.1,<3.0.0" @@ -2416,7 +2416,7 @@ description = "Google Cloud Storage API client library" optional = true python-versions = ">=3.7" groups = ["main"] -markers = "extra == \"google\" and python_version < \"3.14\"" +markers = "extra == \"google\" and python_version <= \"3.13\"" files = [ {file = "google_cloud_storage-3.8.0-py3-none-any.whl", hash = "sha256:78cfeae7cac2ca9441d0d0271c2eb4ebfa21aa4c6944dd0ccac0389e81d955a7"}, {file = "google_cloud_storage-3.8.0.tar.gz", hash = "sha256:cc67952dce84ebc9d44970e24647a58260630b7b64d72360cedaf422d6727f28"}, @@ -3012,7 +3012,7 @@ description = "Human friendly output for text interfaces using Python" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\"" +markers = "python_version <= \"3.13\" and extra == \"extra-proxy\"" files = [ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, @@ -3933,7 +3933,7 @@ description = "" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\"" +markers = "python_version <= \"3.13\" and extra == \"extra-proxy\"" files = [ {file = "ml_dtypes-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1fe8b5b5e70cd67211db94b05cfd58dace592f24489b038dc6f9fe347d2e07d5"}, {file = "ml_dtypes-0.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c09a6d11d8475c2a9fd2bc0695628aec105f97cab3b3a3fb7c9660348ff7d24"}, @@ -4374,7 +4374,7 @@ description = "Fundamental package for array computing in Python" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "(python_version < \"3.14\" or extra == \"mlflow\") and (extra == \"mlflow\" or extra == \"extra-proxy\" or extra == \"semantic-router\") and (python_version >= \"3.10\" or extra == \"extra-proxy\" or extra == \"semantic-router\")" +markers = "(python_version <= \"3.13\" or extra == \"mlflow\") and (python_version < \"3.13\" or extra == \"mlflow\" or extra == \"extra-proxy\" or extra == \"semantic-router\") and (python_version >= \"3.10\" or extra == \"extra-proxy\" or extra == \"semantic-router\") and (extra == \"extra-proxy\" or extra == \"semantic-router\" or extra == \"mlflow\")" files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -5832,7 +5832,7 @@ description = "A python implementation of GNU readline." optional = true python-versions = ">=3.8" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\" and sys_platform == \"win32\"" +markers = "python_version <= \"3.13\" and extra == \"extra-proxy\" and sys_platform == \"win32\"" files = [ {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, @@ -6047,7 +6047,7 @@ description = "Universally unique lexicographically sortable identifier" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\"" +markers = "python_version <= \"3.13\" and extra == \"extra-proxy\"" files = [ {file = "python_ulid-3.1.0-py3-none-any.whl", hash = "sha256:e2cdc979c8c877029b4b7a38a6fba3bc4578e4f109a308419ff4d3ccf0a46619"}, {file = "python_ulid-3.1.0.tar.gz", hash = "sha256:ff0410a598bc5f6b01b602851a3296ede6f91389f913a5d5f8c496003836f636"}, @@ -6194,7 +6194,7 @@ files = [ {file = "redis-5.3.1-py3-none-any.whl", hash = "sha256:dc1909bd24669cc31b5f67a039700b16ec30571096c5f1f0d9d2324bff31af97"}, {file = "redis-5.3.1.tar.gz", hash = "sha256:ca49577a531ea64039b5a36db3d6cd1a0c7a60c34124d46924a45b956e8cf14c"}, ] -markers = {main = "python_version < \"3.14\" and (extra == \"proxy\" or extra == \"extra-proxy\") or extra == \"proxy\""} +markers = {main = "(python_version <= \"3.13\" or extra == \"proxy\") and (python_version < \"3.13\" or extra == \"proxy\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"proxy\")"} [package.dependencies] async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} @@ -6211,7 +6211,7 @@ description = "Python client library and CLI for using Redis as a vector databas optional = true python-versions = "<3.14,>=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"extra-proxy\"" +markers = "python_version <= \"3.13\" and extra == \"extra-proxy\"" files = [ {file = "redisvl-0.4.1-py3-none-any.whl", hash = "sha256:6db5d5bc95b1fe8032a1cdae74ce1c65bc7fe9054e5429b5d34d5a91d28bae5f"}, {file = "redisvl-0.4.1.tar.gz", hash = "sha256:fd6a36426ba94792c0efca20915c31232d4ee3cc58eb23794a62c142696401e6"}, @@ -6429,7 +6429,7 @@ description = "A utility belt for advanced users of python-requests" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"semantic-router\"" +markers = "python_version <= \"3.13\" and extra == \"semantic-router\"" files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -6870,7 +6870,7 @@ description = "Super fast semantic router for AI decision making" optional = true python-versions = "<3.14,>=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"semantic-router\"" +markers = "python_version <= \"3.13\" and extra == \"semantic-router\"" files = [ {file = "semantic_router-0.1.12-py3-none-any.whl", hash = "sha256:94658545f89cc63d2eb7dff6f74bc713b61bbcfe91146b0e4353a383f6790804"}, {file = "semantic_router-0.1.12.tar.gz", hash = "sha256:b63fbb8b9127dcb1763efea17dfa74ab409e626e87c8695b589131af12ef3a65"}, @@ -7337,7 +7337,7 @@ description = "Pretty-print tabular data" optional = true python-versions = ">=3.7" groups = ["main"] -markers = "python_version < \"3.14\" and (extra == \"utils\" or extra == \"extra-proxy\") or extra == \"utils\"" +markers = "(python_version <= \"3.13\" or extra == \"utils\") and (python_version < \"3.13\" or extra == \"utils\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"utils\")" files = [ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, @@ -7370,7 +7370,7 @@ description = "Retry code until it succeeds" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and (extra == \"google\" or extra == \"extra-proxy\") or extra == \"google\"" +markers = "(python_version <= \"3.13\" or extra == \"google\") and (python_version < \"3.13\" or extra == \"google\" or extra == \"extra-proxy\") and (extra == \"extra-proxy\" or extra == \"google\")" files = [ {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, @@ -7581,7 +7581,7 @@ description = "Tornado is a Python web framework and asynchronous networking lib optional = true python-versions = ">=3.9" groups = ["main"] -markers = "python_version < \"3.14\" and extra == \"semantic-router\"" +markers = "python_version <= \"3.13\" and extra == \"semantic-router\"" files = [ {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6"}, {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef"}, @@ -8300,7 +8300,7 @@ type = ["pytest-mypy"] caching = ["diskcache"] extra-proxy = ["a2a-sdk", "azure-identity", "azure-keyvault-secrets", "google-cloud-iam", "google-cloud-kms", "prisma", "redisvl", "resend"] google = ["google-cloud-aiplatform"] -grpc = ["grpcio", "grpcio"] +grpc = ["grpcio"] mlflow = ["mlflow"] proxy = ["PyJWT", "apscheduler", "azure-identity", "azure-storage-blob", "backoff", "boto3", "cryptography", "fastapi", "fastapi-sso", "gunicorn", "litellm-enterprise", "litellm-proxy-extras", "mcp", "orjson", "polars", "pynacl", "pyroscope-io", "python-multipart", "pyyaml", "rich", "rq", "soundfile", "uvicorn", "uvloop", "websockets"] semantic-router = ["semantic-router"] @@ -8309,4 +8309,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "f5b61653bf769baea0593650153760a45242718ab3d505dac6dbe66b450a3347" +content-hash = "f507b7c5060793a3325171c5245376057fc0f61a3a9443e9acd88d23a939a14a" From 006d48102563de962f62a8a118a4aa3919858f90 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 1 Apr 2026 16:15:32 -0700 Subject: [PATCH 16/32] [Fix] Remove neon CLI dependency and pin all JS dependencies Remove @neondatabase/api-client and neonctl to address CVE-2026-25639 (axios supply chain vulnerability). Pin all JS dependencies to exact versions across all package.json files to prevent future supply chain attacks via semver range resolution. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 24 +-- ci_cd/security_scans.sh | 1 - docs/my-website/package-lock.json | 25 +-- docs/my-website/package.json | 18 +- litellm-js/proxy/package.json | 8 +- litellm-js/spend-logs/package-lock.json | 8 +- litellm-js/spend-logs/package.json | 8 +- package.json | 14 +- tests/proxy_admin_ui_tests/package.json | 4 +- .../ui_unit_tests/package.json | 28 ++-- ui/litellm-dashboard/package-lock.json | 155 ++++++------------ ui/litellm-dashboard/package.json | 105 ++++++------ .../scripts/e2e_tests/neonHelperScripts.ts | 56 ------- 13 files changed, 158 insertions(+), 296 deletions(-) delete mode 100644 ui/litellm-dashboard/scripts/e2e_tests/neonHelperScripts.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 5bbabad9107..307247651e7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3233,31 +3233,9 @@ jobs: name: Install Playwright Browsers command: | npx playwright install - - run: - name: Install Neon CLI - command: | - npm i -g neonctl - - run: - name: Create Neon branch - command: | - export EXPIRES_AT=$(date -u -d "+3 hours" +"%Y-%m-%dT%H:%M:%SZ") - echo "Expires at: $EXPIRES_AT" - neon branches create \ - --project-id $NEON_PROJECT_ID \ - --name preview/commit-${CIRCLE_SHA1:0:7}-<< parameters.browser >> \ - --expires-at $EXPIRES_AT \ - --parent br-fancy-paper-ad1olsb3 \ - --api-key $NEON_API_KEY || true - run: name: Run Docker container command: | - E2E_UI_TEST_DATABASE_URL=$(neon connection-string \ - --project-id $NEON_PROJECT_ID \ - --api-key $NEON_API_KEY \ - --branch preview/commit-${CIRCLE_SHA1:0:7}-<< parameters.browser >> \ - --database-name yuneng-trial-db \ - --role neondb_owner) - echo $E2E_UI_TEST_DATABASE_URL docker run -d \ -p 4000:4000 \ -e DATABASE_URL=$E2E_UI_TEST_DATABASE_URL \ @@ -3531,7 +3509,7 @@ workflows: only: - main - /litellm_.*/ - # - e2e_ui_testing: # migrate to dynamic db - currently requires neon cli + # - e2e_ui_testing: # name: e2e_ui_testing_chromium # browser: chromium # context: e2e_ui_tests diff --git a/ci_cd/security_scans.sh b/ci_cd/security_scans.sh index ee33393c8b1..2138fca6cd5 100755 --- a/ci_cd/security_scans.sh +++ b/ci_cd/security_scans.sh @@ -160,7 +160,6 @@ run_grype_scans() { "CVE-2026-0775" # npm cli incorrect permission assignment - no fix available yet, npm is only used at build/prisma-generate time "GHSA-3ppc-4f35-3m26" # minimatch ReDoS via repeated wildcards - from nodejs_wheel bundled npm, not used in application runtime code "GHSA-83g3-92jg-28cx" # tar arbitrary file read/write via hardlink - from nodejs_wheel bundled npm, not used in application runtime code - "CVE-2026-25639" # axios DoS via __proto__ in mergeConfig - transitive dev dep via @neondatabase/api-client, not imported in application code "CVE-2026-2297" # Python 3.13 SourcelessFileLoader audit hook bypass - no fix available in base image "GHSA-qffp-2rhf-9h96" # tar hardlink path traversal - from nodejs_wheel bundled npm, not used in application runtime code "CVE-2026-2673" # OpenSSL 3.6.1 TLS 1.3 key exchange group negotiation issue - no fix available yet diff --git a/docs/my-website/package-lock.json b/docs/my-website/package-lock.json index a3e9cb61428..56684b737de 100644 --- a/docs/my-website/package-lock.json +++ b/docs/my-website/package-lock.json @@ -13,18 +13,18 @@ "@docusaurus/plugin-ideal-image": "3.8.1", "@docusaurus/preset-classic": "3.8.1", "@docusaurus/theme-mermaid": "3.8.1", - "@inkeep/cxkit-docusaurus": "^0.5.89", - "@mdx-js/react": "^3.0.0", - "clsx": "^1.2.1", - "prism-react-renderer": "^1.3.5", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0", - "sharp": "^0.32.6", - "uuid": "^9.0.1" + "@inkeep/cxkit-docusaurus": "0.5.107", + "@mdx-js/react": "3.1.1", + "clsx": "1.2.1", + "prism-react-renderer": "1.3.5", + "react": "18.3.1", + "react-dom": "18.3.1", + "sharp": "0.32.6", + "uuid": "9.0.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.8.1", - "dotenv": "^16.4.5" + "dotenv": "16.6.1" }, "engines": { "node": ">=16.14", @@ -20403,13 +20403,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/search-insights": { - "version": "2.17.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", - "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", - "license": "MIT", - "peer": true - }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", diff --git a/docs/my-website/package.json b/docs/my-website/package.json index 2802d24b57e..73ff62dcb43 100644 --- a/docs/my-website/package.json +++ b/docs/my-website/package.json @@ -19,18 +19,18 @@ "@docusaurus/plugin-ideal-image": "3.8.1", "@docusaurus/preset-classic": "3.8.1", "@docusaurus/theme-mermaid": "3.8.1", - "@inkeep/cxkit-docusaurus": "^0.5.89", - "@mdx-js/react": "^3.0.0", - "clsx": "^1.2.1", - "prism-react-renderer": "^1.3.5", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0", - "sharp": "^0.32.6", - "uuid": "^9.0.1" + "@inkeep/cxkit-docusaurus": "0.5.107", + "@mdx-js/react": "3.1.1", + "clsx": "1.2.1", + "prism-react-renderer": "1.3.5", + "react": "18.3.1", + "react-dom": "18.3.1", + "sharp": "0.32.6", + "uuid": "9.0.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.8.1", - "dotenv": "^16.4.5" + "dotenv": "16.6.1" }, "browserslist": { "production": [ diff --git a/litellm-js/proxy/package.json b/litellm-js/proxy/package.json index f63cf36d2ed..7195c6b3601 100644 --- a/litellm-js/proxy/package.json +++ b/litellm-js/proxy/package.json @@ -4,11 +4,11 @@ "deploy": "wrangler deploy --minify src/index.ts" }, "dependencies": { - "hono": "^4.1.4", - "openai": "^4.29.2" + "hono": "4.1.4", + "openai": "4.29.2" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240208.0", - "wrangler": "^3.32.0" + "@cloudflare/workers-types": "4.20240208.0", + "wrangler": "3.32.0" } } diff --git a/litellm-js/spend-logs/package-lock.json b/litellm-js/spend-logs/package-lock.json index b24ff0a4940..3784fb78658 100644 --- a/litellm-js/spend-logs/package-lock.json +++ b/litellm-js/spend-logs/package-lock.json @@ -5,12 +5,12 @@ "packages": { "": { "dependencies": { - "@hono/node-server": "^1.10.1", - "hono": "^4.12.7" + "@hono/node-server": "1.19.6", + "hono": "4.12.7" }, "devDependencies": { - "@types/node": "^20.11.17", - "tsx": "^4.7.1" + "@types/node": "20.19.25", + "tsx": "4.20.6" } }, "node_modules/@esbuild/aix-ppc64": { diff --git a/litellm-js/spend-logs/package.json b/litellm-js/spend-logs/package.json index 8bccbdba27b..742dafe2b8e 100644 --- a/litellm-js/spend-logs/package.json +++ b/litellm-js/spend-logs/package.json @@ -3,11 +3,11 @@ "dev": "tsx watch src/index.ts" }, "dependencies": { - "@hono/node-server": "^1.10.1", - "hono": "^4.12.7" + "@hono/node-server": "1.19.6", + "hono": "4.12.7" }, "devDependencies": { - "@types/node": "^20.11.17", - "tsx": "^4.7.1" + "@types/node": "20.19.25", + "tsx": "4.20.6" } } diff --git a/package.json b/package.json index 9a7ebf4ae05..84e6e51f86b 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { "dependencies": { - "prism-react-renderer": "^2.4.1", - "prisma": "^5.17.0", - "react-copy-to-clipboard": "^5.1.0" + "prism-react-renderer": "2.4.1", + "prisma": "5.17.0", + "react-copy-to-clipboard": "5.1.0" }, "devDependencies": { - "@testing-library/jest-dom": "^6.8.0", - "@testing-library/react": "^14.3.1", - "@types/react-copy-to-clipboard": "^5.0.7", - "jest": "^29.7.0" + "@testing-library/jest-dom": "6.8.0", + "@testing-library/react": "14.3.1", + "@types/react-copy-to-clipboard": "5.0.7", + "jest": "29.7.0" }, "overrides": { "glob": "13.0.0", diff --git a/tests/proxy_admin_ui_tests/package.json b/tests/proxy_admin_ui_tests/package.json index 20dfed7a8a5..5933490fb1d 100644 --- a/tests/proxy_admin_ui_tests/package.json +++ b/tests/proxy_admin_ui_tests/package.json @@ -8,7 +8,7 @@ "author": "", "license": "ISC", "devDependencies": { - "@playwright/test": "^1.47.2", - "@types/node": "^22.5.5" + "@playwright/test": "1.56.1", + "@types/node": "22.19.1" } } diff --git a/tests/proxy_admin_ui_tests/ui_unit_tests/package.json b/tests/proxy_admin_ui_tests/ui_unit_tests/package.json index c6a3e6e260e..1c6dce56afe 100644 --- a/tests/proxy_admin_ui_tests/ui_unit_tests/package.json +++ b/tests/proxy_admin_ui_tests/ui_unit_tests/package.json @@ -6,22 +6,22 @@ "test:watch": "jest --watch" }, "devDependencies": { - "@testing-library/react": "^14.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@types/jest": "^29.5.0", - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^29.5.0", - "jest-environment-jsdom": "^29.5.0", - "ts-jest": "^29.1.0", - "typescript": "^5.0.0" + "@testing-library/react": "14.3.1", + "@testing-library/jest-dom": "6.9.1", + "@types/jest": "29.5.14", + "@types/react": "18.3.27", + "@types/react-dom": "18.3.7", + "identity-obj-proxy": "3.0.0", + "jest": "29.7.0", + "jest-environment-jsdom": "29.7.0", + "ts-jest": "29.4.5", + "typescript": "5.9.3" }, "dependencies": { - "antd": "^5.12.5", - "@ant-design/icons": "^5.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "antd": "5.29.1", + "@ant-design/icons": "5.6.1", + "react": "18.3.1", + "react-dom": "18.3.1" }, "overrides": { "glob": "13.0.0", diff --git a/ui/litellm-dashboard/package-lock.json b/ui/litellm-dashboard/package-lock.json index 2b62c1c16bb..58b0a6b6117 100644 --- a/ui/litellm-dashboard/package-lock.json +++ b/ui/litellm-dashboard/package-lock.json @@ -8,66 +8,65 @@ "name": "litellm-dashboard", "version": "0.1.0", "dependencies": { - "@anthropic-ai/sdk": "^0.54.0", - "@headlessui/tailwindcss": "^0.2.0", - "@heroicons/react": "^1.0.6", - "@remixicon/react": "^4.1.1", - "@tanstack/react-pacer": "^0.2.0", - "@tanstack/react-query": "^5.64.1", - "@tanstack/react-table": "^8.20.6", - "@tremor/react": "^3.13.3", - "@types/papaparse": "^5.3.15", - "antd": "^5.13.2", - "cva": "^1.0.0-beta.3", - "dayjs": "^1.11.19", - "jwt-decode": "^4.0.0", - "lucide-react": "^0.513.0", - "moment": "^2.30.1", - "next": "^16.1.7", - "openai": "^4.93.0", - "papaparse": "^5.5.2", - "react": "^18.3.1", - "react-copy-to-clipboard": "^5.1.0", - "react-dom": "^18.3.1", - "react-json-view-lite": "^2.5.0", - "react-markdown": "^9.0.1", - "react-syntax-highlighter": "^15.6.6", - "remark-gfm": "^4.0.1", - "tailwind-merge": "^3.2.0", - "uuid": "^11.1.0" + "@anthropic-ai/sdk": "0.54.0", + "@headlessui/tailwindcss": "0.2.2", + "@heroicons/react": "1.0.6", + "@remixicon/react": "4.9.0", + "@tanstack/react-pacer": "0.2.0", + "@tanstack/react-query": "5.90.20", + "@tanstack/react-table": "8.21.3", + "@tremor/react": "3.18.7", + "@types/papaparse": "5.5.2", + "antd": "5.29.3", + "cva": "1.0.0-beta.4", + "dayjs": "1.11.19", + "jwt-decode": "4.0.0", + "lucide-react": "0.513.0", + "moment": "2.30.1", + "next": "16.1.7", + "openai": "4.104.0", + "papaparse": "5.5.3", + "react": "18.3.1", + "react-copy-to-clipboard": "5.1.0", + "react-dom": "18.3.1", + "react-json-view-lite": "2.5.0", + "react-markdown": "9.1.0", + "react-syntax-highlighter": "15.6.6", + "remark-gfm": "4.0.1", + "tailwind-merge": "3.4.0", + "uuid": "11.1.0" }, "devDependencies": { - "@neondatabase/api-client": "^2.6.0", - "@playwright/test": "^1.57.0", - "@tailwindcss/forms": "^0.5.7", - "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.8.0", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@types/babel__traverse": "^7.28.0", - "@types/lodash": "^4.17.15", + "@playwright/test": "1.58.1", + "@tailwindcss/forms": "0.5.11", + "@testing-library/dom": "10.4.1", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/react": "16.3.2", + "@testing-library/user-event": "14.6.1", + "@types/babel__traverse": "7.28.0", + "@types/lodash": "4.17.23", "@types/node": "20.19.37", "@types/react": "18.2.48", - "@types/react-copy-to-clipboard": "^5.0.7", - "@types/react-dom": "^18", - "@types/react-syntax-highlighter": "^15.5.11", - "@types/uuid": "^10.0.0", - "@vitest/coverage-v8": "^3.2.4", - "@vitest/ui": "^3.2.4", - "autoprefixer": "^10.4.17", - "dotenv": "^17.2.3", - "eslint": "^9.39.2", + "@types/react-copy-to-clipboard": "5.0.7", + "@types/react-dom": "18.3.7", + "@types/react-syntax-highlighter": "15.5.13", + "@types/uuid": "10.0.0", + "@vitest/coverage-v8": "3.2.4", + "@vitest/ui": "3.2.4", + "autoprefixer": "10.4.24", + "dotenv": "17.2.3", + "eslint": "9.39.2", "eslint-config-next": "15.5.10", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-unused-imports": "^4.2.0", - "jsdom": "^27.0.0", - "knip": "^5.83.1", - "postcss": "^8.4.33", + "eslint-config-prettier": "10.1.8", + "eslint-plugin-unused-imports": "4.3.0", + "jsdom": "27.4.0", + "knip": "5.83.1", + "postcss": "8.5.6", "prettier": "3.2.5", - "tailwindcss": "^3.4.1", + "tailwindcss": "3.4.19", "typescript": "5.9.3", - "vite": "^7.1.11", - "vitest": "^3.2.4" + "vite": "7.3.1", + "vitest": "3.2.4" }, "engines": { "node": ">=18.17.0", @@ -1822,16 +1821,6 @@ "@tybys/wasm-util": "^0.10.0" } }, - "node_modules/@neondatabase/api-client": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@neondatabase/api-client/-/api-client-2.6.0.tgz", - "integrity": "sha512-NxKE+EFcVwxXU3jj8I/WgueXSyzrXV85AV0nb2SeoKtOa3dlEcTylsdOsMsMeZZeFfQXLyiCOm2nAduGZn9olA==", - "dev": true, - "license": "MIT", - "dependencies": { - "axios": "^1.9.0" - } - }, "node_modules/@next/env": { "version": "16.1.7", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.7.tgz", @@ -4684,18 +4673,6 @@ "node": ">=4" } }, - "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -6630,27 +6607,6 @@ "dev": true, "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -10281,13 +10237,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index 7b763eaa66a..dfad2a1e795 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -20,66 +20,65 @@ "knip:fix": "knip --fix" }, "dependencies": { - "@anthropic-ai/sdk": "^0.54.0", - "@headlessui/tailwindcss": "^0.2.0", - "@heroicons/react": "^1.0.6", - "@remixicon/react": "^4.1.1", - "@tanstack/react-pacer": "^0.2.0", - "@tanstack/react-query": "^5.64.1", - "@tanstack/react-table": "^8.20.6", - "@tremor/react": "^3.13.3", - "@types/papaparse": "^5.3.15", - "antd": "^5.13.2", - "cva": "^1.0.0-beta.3", - "dayjs": "^1.11.19", - "jwt-decode": "^4.0.0", - "lucide-react": "^0.513.0", - "moment": "^2.30.1", - "next": "^16.1.7", - "openai": "^4.93.0", - "papaparse": "^5.5.2", - "react": "^18.3.1", - "react-copy-to-clipboard": "^5.1.0", - "react-dom": "^18.3.1", - "react-json-view-lite": "^2.5.0", - "react-markdown": "^9.0.1", - "react-syntax-highlighter": "^15.6.6", - "remark-gfm": "^4.0.1", - "tailwind-merge": "^3.2.0", - "uuid": "^11.1.0" + "@anthropic-ai/sdk": "0.54.0", + "@headlessui/tailwindcss": "0.2.2", + "@heroicons/react": "1.0.6", + "@remixicon/react": "4.9.0", + "@tanstack/react-pacer": "0.2.0", + "@tanstack/react-query": "5.90.20", + "@tanstack/react-table": "8.21.3", + "@tremor/react": "3.18.7", + "@types/papaparse": "5.5.2", + "antd": "5.29.3", + "cva": "1.0.0-beta.4", + "dayjs": "1.11.19", + "jwt-decode": "4.0.0", + "lucide-react": "0.513.0", + "moment": "2.30.1", + "next": "16.1.7", + "openai": "4.104.0", + "papaparse": "5.5.3", + "react": "18.3.1", + "react-copy-to-clipboard": "5.1.0", + "react-dom": "18.3.1", + "react-json-view-lite": "2.5.0", + "react-markdown": "9.1.0", + "react-syntax-highlighter": "15.6.6", + "remark-gfm": "4.0.1", + "tailwind-merge": "3.4.0", + "uuid": "11.1.0" }, "devDependencies": { - "@neondatabase/api-client": "^2.6.0", - "@playwright/test": "^1.57.0", - "@tailwindcss/forms": "^0.5.7", - "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.8.0", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@types/babel__traverse": "^7.28.0", - "@types/lodash": "^4.17.15", + "@playwright/test": "1.58.1", + "@tailwindcss/forms": "0.5.11", + "@testing-library/dom": "10.4.1", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/react": "16.3.2", + "@testing-library/user-event": "14.6.1", + "@types/babel__traverse": "7.28.0", + "@types/lodash": "4.17.23", "@types/node": "20.19.37", "@types/react": "18.2.48", - "@types/react-copy-to-clipboard": "^5.0.7", - "@types/react-dom": "^18", - "@types/react-syntax-highlighter": "^15.5.11", - "@types/uuid": "^10.0.0", - "@vitest/coverage-v8": "^3.2.4", - "@vitest/ui": "^3.2.4", - "autoprefixer": "^10.4.17", - "dotenv": "^17.2.3", - "eslint": "^9.39.2", + "@types/react-copy-to-clipboard": "5.0.7", + "@types/react-dom": "18.3.7", + "@types/react-syntax-highlighter": "15.5.13", + "@types/uuid": "10.0.0", + "@vitest/coverage-v8": "3.2.4", + "@vitest/ui": "3.2.4", + "autoprefixer": "10.4.24", + "dotenv": "17.2.3", + "eslint": "9.39.2", "eslint-config-next": "15.5.10", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-unused-imports": "^4.2.0", - "jsdom": "^27.0.0", - "knip": "^5.83.1", - "postcss": "^8.4.33", + "eslint-config-prettier": "10.1.8", + "eslint-plugin-unused-imports": "4.3.0", + "jsdom": "27.4.0", + "knip": "5.83.1", + "postcss": "8.5.6", "prettier": "3.2.5", - "tailwindcss": "^3.4.1", + "tailwindcss": "3.4.19", "typescript": "5.9.3", - "vite": "^7.1.11", - "vitest": "^3.2.4" + "vite": "7.3.1", + "vitest": "3.2.4" }, "overrides": { "prismjs": "1.30.0", diff --git a/ui/litellm-dashboard/scripts/e2e_tests/neonHelperScripts.ts b/ui/litellm-dashboard/scripts/e2e_tests/neonHelperScripts.ts deleted file mode 100644 index 089ad4e7926..00000000000 --- a/ui/litellm-dashboard/scripts/e2e_tests/neonHelperScripts.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { createApiClient, EndpointType } from "@neondatabase/api-client"; -import { config } from "dotenv"; -import { resolve } from "path"; - -const envPaths = [ - resolve(process.cwd(), "../../.env"), // project root -]; - -for (const envPath of envPaths) { - config({ path: envPath }); -} - -const NEON_API_KEY = process.env.NEON_API_KEY!; -const PROJECT_ID = process.env.NEON_PROJECT_ID!; -const PARENT_BRANCH = process.env.NEON_PARENT_BRANCH_ID!; -const NEON_E2E_UI_TEST_DB_NAME = process.env.NEON_E2E_UI_TEST_DB_NAME!; - -const apiClient = createApiClient({ - apiKey: NEON_API_KEY, -}); - -export async function createNeonE2ETestingBranch(projectId: string, parentBranchId?: string, expireAt?: string) { - try { - const response = await apiClient.createProjectBranch(projectId, { - branch: { - name: `e2e-local-${crypto.randomUUID()}`, - parent_id: parentBranchId, - expires_at: expireAt ?? new Date(Date.now() + 1000 * 60 * 30).toISOString(), - }, - endpoints: [ - { - type: EndpointType.ReadWrite, - autoscaling_limit_min_cu: 0.25, - autoscaling_limit_max_cu: 1, - }, - ], - }); - return response; - } catch (error) { - throw error; - } -} - -export async function getNeonE2ETestingBranchConnectionString() { - const createBranchResponse = await createNeonE2ETestingBranch(PROJECT_ID, PARENT_BRANCH); - const projectId = createBranchResponse.data.branch.project_id; - const response = await apiClient.getConnectionUri({ - database_name: NEON_E2E_UI_TEST_DB_NAME, - role_name: "neondb_owner", - projectId: projectId, - }); - console.log("connection string:", response.data.uri); - return response.data.uri; -} - -getNeonE2ETestingBranchConnectionString(); From adedae2cfac11051a2be7e3bddd5122d3ae9801b Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Thu, 2 Apr 2026 04:10:30 +0200 Subject: [PATCH 17/32] fix(auth): enforce budget for models not in cost map (#24949) * fix(auth): enforce budget for models not in cost map * fix log injection in debug messages + isolate test global state --- litellm/proxy/auth/auth_checks.py | 46 +++++++- litellm/router.py | 4 +- litellm/types/utils.py | 4 +- .../test_unmapped_model_budget_enforcement.py | 108 ++++++++++++++++++ 4 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 tests/test_litellm/proxy/auth/test_unmapped_model_budget_enforcement.py diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index c00a351bdd8..68bde8434a6 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -165,9 +165,24 @@ def _is_model_cost_zero( ) return False - # This model has zero cost explicitly configured + # Costs are 0 — verify this is from explicit configuration, + # not from defaulted sparse auto-registration entries. + # See: https://github.com/BerriAI/litellm/issues/24770 + safe_name = str(model_name).replace("\n", "").replace("\r", "") + if not _is_cost_explicitly_configured(model_name, llm_router): + verbose_proxy_logger.debug( + "Model %s has zero cost but no explicit cost " + "configuration in model_cost entry — treating as unknown " + "cost (enforce budget)", + safe_name, + ) + return False + verbose_proxy_logger.debug( - f"Model {model_name} has zero cost explicitly configured (input: {input_cost}, output: {output_cost})" + "Model %s has zero cost explicitly configured (input: %s, output: %s)", + safe_name, + input_cost, + output_cost, ) except Exception as e: @@ -181,6 +196,33 @@ def _is_model_cost_zero( return True +def _is_cost_explicitly_configured( + model: str, llm_router: "Router" +) -> bool: + """ + Check if any deployment in the model group has cost fields explicitly + set in its litellm.model_cost entry. + + When Router._create_deployment() registers a model not in the global + cost map, it creates a sparse entry like {"id": ""} with no cost + fields. _get_model_info_helper() then defaults missing costs to 0. + This function detects that scenario by checking the raw model_cost entry. + """ + for deployment in llm_router.model_list: + if deployment.get("model_name") != model: + continue + model_id = deployment.get("model_info", {}).get("id") + if model_id is None: + continue + raw_entry = litellm.model_cost.get(model_id, {}) + if ( + "input_cost_per_token" in raw_entry + or "output_cost_per_token" in raw_entry + ): + return True + return False + + async def _run_project_checks( project_object: Optional[LiteLLM_ProjectTableCachedObj], _model: Optional[Union[str, List[str]]], diff --git a/litellm/router.py b/litellm/router.py index 6cc6bad9def..586d5961b94 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -7808,8 +7808,8 @@ class Router: max_tokens=None, max_input_tokens=None, max_output_tokens=None, - input_cost_per_token=0, - output_cost_per_token=0, + input_cost_per_token=None, + output_cost_per_token=None, litellm_provider=llm_provider, mode=mode, supported_openai_params=supported_openai_params, diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 82557513a8a..3f6e6e5aa5a 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -169,7 +169,7 @@ class ModelInfoBase(ProviderSpecificModelInfo, total=False): max_tokens: Required[Optional[int]] max_input_tokens: Required[Optional[int]] max_output_tokens: Required[Optional[int]] - input_cost_per_token: Required[float] + input_cost_per_token: Required[Optional[float]] input_cost_per_token_flex: Optional[float] # OpenAI flex service tier pricing input_cost_per_token_priority: Optional[ float @@ -206,7 +206,7 @@ class ModelInfoBase(ProviderSpecificModelInfo, total=False): input_cost_per_second: Optional[float] # for OpenAI Speech models input_cost_per_token_batches: Optional[float] output_cost_per_token_batches: Optional[float] - output_cost_per_token: Required[float] + output_cost_per_token: Required[Optional[float]] output_cost_per_token_flex: Optional[float] # OpenAI flex service tier pricing output_cost_per_token_priority: Optional[ float diff --git a/tests/test_litellm/proxy/auth/test_unmapped_model_budget_enforcement.py b/tests/test_litellm/proxy/auth/test_unmapped_model_budget_enforcement.py new file mode 100644 index 00000000000..e9f4111f83d --- /dev/null +++ b/tests/test_litellm/proxy/auth/test_unmapped_model_budget_enforcement.py @@ -0,0 +1,108 @@ +""" +Test that models not in the cost map do NOT bypass budget enforcement. + +Regression test for the bug where unmapped models got fallback costs of 0, +causing _is_model_cost_zero() to return True and skip all budget checks. + +See: https://github.com/BerriAI/litellm/issues/24770 +""" + +import copy + +import litellm +from litellm.proxy.auth.auth_checks import _is_model_cost_zero +from litellm.router import Router + + +class TestUnmappedModelBudgetEnforcement: + """Unmapped models must NOT bypass budget checks.""" + + def setup_method(self): + """Snapshot litellm.model_cost before each test.""" + self._saved_model_cost = copy.deepcopy(litellm.model_cost) + + def teardown_method(self): + """Restore litellm.model_cost after each test.""" + litellm.model_cost = self._saved_model_cost + + def test_unmapped_model_enforces_budget(self): + """A model not in litellm.model_cost should have budget enforced.""" + router = Router( + model_list=[ + { + "model_name": "custom-model", + "litellm_params": { + "model": "openai/totally-nonexistent-model-xyz", + "api_key": "sk-fake", + }, + }, + ] + ) + result = _is_model_cost_zero(model="custom-model", llm_router=router) + assert result is False, ( + "Unmapped model should enforce budget (return False), " + "not bypass it (return True)" + ) + + def test_explicitly_free_model_bypasses_budget(self): + """A model with explicit cost=0 in model_info should bypass budget.""" + router = Router( + model_list=[ + { + "model_name": "free-model", + "litellm_params": { + "model": "ollama/llama2", + "api_base": "http://localhost:11434", + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + }, + "model_info": { + "id": "free-model-id", + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + }, + }, + ] + ) + result = _is_model_cost_zero(model="free-model", llm_router=router) + assert result is True, ( + "Explicitly free model should bypass budget (return True)" + ) + + def test_known_paid_model_enforces_budget(self): + """A model in the cost map with non-zero costs should enforce budget.""" + router = Router( + model_list=[ + { + "model_name": "paid-model", + "litellm_params": { + "model": "openai/gpt-4o-mini", + "api_key": "sk-fake", + }, + }, + ] + ) + result = _is_model_cost_zero(model="paid-model", llm_router=router) + assert result is False, ( + "Known paid model should enforce budget (return False)" + ) + + def test_unmapped_model_with_litellm_params_pricing(self): + """A model with cost=0 in litellm_params (not model_info) should bypass budget.""" + router = Router( + model_list=[ + { + "model_name": "free-via-params", + "litellm_params": { + "model": "openai/nonexistent-but-free-model", + "api_key": "sk-fake", + "input_cost_per_token": 0.0, + "output_cost_per_token": 0.0, + }, + }, + ] + ) + result = _is_model_cost_zero(model="free-via-params", llm_router=router) + assert result is True, ( + "Model with explicit cost=0 in litellm_params should bypass budget" + ) From d1df4e838b3d105ebd78865ee879ebaa7e65b6a6 Mon Sep 17 00:00:00 2001 From: David Chen Date: Wed, 1 Apr 2026 19:22:54 -0700 Subject: [PATCH 18/32] Litellm fix update bedrock models (#24947) * update bedrock models in tests * updated more tests and model_prices_and_context_window * fix model id and pricing * replace more sonnet models * update tests * git push * update pricing * flaky total cost * monkey patch * relax the cost change * fix and revert some changes * revert the pricing * chore: move cost/pricing changes to bedrock-cost-fixes branch * chore: split Bedrock file-api beta stripping to separate branch Removes strip_unsupported_file_api_betas_for_bedrock_invoke from this branch; see litellm_bedrock_invoke_strip_file_api_betas for that fix. Made-with: Cursor --- .../claude_code_quickstart/guide.md | 2 +- cookbook/misc/test_responses_api.py | 4 +- .../my-website/docs/anthropic_count_tokens.md | 2 +- .../docs/completion/computer_use.md | 6 +- .../docs/completion/document_understanding.md | 18 +- .../completion/provider_specific_params.md | 2 +- docs/my-website/docs/index.md | 2 +- docs/my-website/docs/oidc.md | 2 +- docs/my-website/docs/providers/bedrock.md | 20 +-- .../docs/tutorials/claude_responses_api.md | 2 +- .../tutorials/github_copilot_integration.md | 2 +- .../docs/tutorials/google_genai_sdk.md | 2 +- .../docs/tutorials/litellm_gemini_cli.md | 4 +- .../docs/tutorials/litellm_qwen_code_cli.md | 4 +- .../anthropic_claude3_transformation.py | 3 - .../websearch_interception_config.yaml | 2 +- litellm/setup_wizard.py | 2 +- .../litellm_utils_tests/test_health_check.py | 4 +- .../test_bedrock_anthropic_regression.py | 12 +- .../test_bedrock_common_utils.py | 14 +- .../test_bedrock_completion.py | 36 ++-- .../llm_translation/test_bedrock_govcloud.py | 170 +++++++++--------- .../test_bedrock_invoke_tests.py | 2 +- .../test_anthropic_prompt_caching.py | 2 +- tests/local_testing/test_caching.py | 4 +- tests/local_testing/test_get_llm_provider.py | 4 +- tests/local_testing/test_get_model_info.py | 8 +- .../test_provider_specific_config.py | 4 +- tests/local_testing/test_router_timeout.py | 2 +- tests/local_testing/test_timeout.py | 2 +- .../whitelisted_bedrock_models.txt | 16 +- .../completion_with_bedrock_call.json | 10 +- .../test_langfuse_e2e_test.py | 4 +- .../test_bedrock_batches_api.py | 2 +- tests/pass_through_tests/test_vertex.test.js | 103 ++++++----- ...test_bedrock_converse_structured_output.py | 2 +- .../test_bedrock_invoke_structured_output.py | 2 +- .../test_anthropic_messages_passthrough.py | 2 +- .../test_websearch_interception_e2e.py | 12 +- .../test_websearch_interception_handler.py | 6 +- .../test_litellm_logging.py | 2 +- .../test_streaming_handler.py | 8 +- .../chat/test_converse_transformation.py | 139 +++++++------- .../expected_bedrock_batch_completions.jsonl | 4 +- .../bedrock/test_anthropic_beta_support.py | 25 +-- .../llms/bedrock/test_bedrock_common_utils.py | 4 +- .../llms/chat/test_converse_handler.py | 8 +- .../passthrough/test_passthrough_main.py | 2 +- .../test_team_endpoints.py | 8 +- .../test_anthropic_beta_headers_filtering.py | 2 +- tests/test_litellm/test_main.py | 6 +- tests/test_litellm/test_router.py | 2 +- tests/test_litellm/test_utils.py | 32 ++-- tests/test_users.py | 6 +- 54 files changed, 387 insertions(+), 363 deletions(-) diff --git a/cookbook/ai_coding_tool_guides/claude_code_quickstart/guide.md b/cookbook/ai_coding_tool_guides/claude_code_quickstart/guide.md index 3d6c75498b1..b2d81be25bb 100644 --- a/cookbook/ai_coding_tool_guides/claude_code_quickstart/guide.md +++ b/cookbook/ai_coding_tool_guides/claude_code_quickstart/guide.md @@ -230,7 +230,7 @@ model_list: # AWS Bedrock - model_name: claude-bedrock litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 diff --git a/cookbook/misc/test_responses_api.py b/cookbook/misc/test_responses_api.py index 5fd19c6f66f..62e4e2cf62e 100644 --- a/cookbook/misc/test_responses_api.py +++ b/cookbook/misc/test_responses_api.py @@ -20,7 +20,7 @@ base64_image = encode_image(image_path) response = client.responses.create( - model="bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", input=[ { "role": "user", @@ -43,7 +43,7 @@ print("sleeping for 20 seconds...") time.sleep(20) print("making follow up request for existing id") response2 = client.responses.create( - model="bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", previous_response_id=response.id, input="ok, and what objects are in the image?" ) diff --git a/docs/my-website/docs/anthropic_count_tokens.md b/docs/my-website/docs/anthropic_count_tokens.md index 5985516d69c..a62e46f156a 100644 --- a/docs/my-website/docs/anthropic_count_tokens.md +++ b/docs/my-website/docs/anthropic_count_tokens.md @@ -96,7 +96,7 @@ model_list: - model_name: claude-bedrock litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_region_name: us-west-2 ``` diff --git a/docs/my-website/docs/completion/computer_use.md b/docs/my-website/docs/completion/computer_use.md index ed09a73b219..400f108f97e 100644 --- a/docs/my-website/docs/completion/computer_use.md +++ b/docs/my-website/docs/completion/computer_use.md @@ -80,7 +80,7 @@ model_list: api_key: os.environ/ANTHROPIC_API_KEY - model_name: claude-bedrock # Bedrock Anthropic model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-west-2 @@ -153,7 +153,7 @@ import litellm assert litellm.supports_computer_use(model="anthropic/claude-3-5-sonnet-latest") == True assert litellm.supports_computer_use(model="anthropic/claude-3-7-sonnet-20250219") == True -assert litellm.supports_computer_use(model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0") == True +assert litellm.supports_computer_use(model="bedrock/anthropic.claude-haiku-4-5-20251001:0") == True assert litellm.supports_computer_use(model="vertex_ai/claude-3-5-sonnet") == True assert litellm.supports_computer_use(model="openai/gpt-4") == False ``` @@ -171,7 +171,7 @@ model_list: api_key: os.environ/ANTHROPIC_API_KEY - model_name: claude-bedrock # Bedrock Anthropic model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-west-2 diff --git a/docs/my-website/docs/completion/document_understanding.md b/docs/my-website/docs/completion/document_understanding.md index 172e0792801..f510a33f79a 100644 --- a/docs/my-website/docs/completion/document_understanding.md +++ b/docs/my-website/docs/completion/document_understanding.md @@ -32,7 +32,7 @@ os.environ["AWS_REGION_NAME"] = "" file_url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" # model -model = "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0" +model = "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0" file_content = [ {"type": "text", "text": "What's this file about?"}, @@ -63,7 +63,7 @@ assert response is not None model_list: - model_name: bedrock-model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME @@ -122,7 +122,7 @@ encoded_file = base64.b64encode(file_data).decode("utf-8") base64_url = f"data:application/pdf;base64,{encoded_file}" # model -model = "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0" +model = "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0" file_content = [ {"type": "text", "text": "What's this file about?"}, @@ -153,7 +153,7 @@ assert response is not None model_list: - model_name: bedrock-model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME @@ -210,7 +210,7 @@ os.environ["AWS_REGION_NAME"] = "" file_url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" # model -model = "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0" +model = "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0" file_content = [ {"type": "text", "text": "What's this file about?"}, @@ -242,7 +242,7 @@ assert response is not None model_list: - model_name: bedrock-model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME @@ -350,10 +350,10 @@ curl -X POST 'http://0.0.0.0:4000/chat/completions' \ -Use `litellm.supports_pdf_input(model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0")` -> returns `True` if model can accept pdf input +Use `litellm.supports_pdf_input(model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0")` -> returns `True` if model can accept pdf input ```python -assert litellm.supports_pdf_input(model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0") == True +assert litellm.supports_pdf_input(model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0") == True ``` @@ -365,7 +365,7 @@ assert litellm.supports_pdf_input(model="bedrock/anthropic.claude-3-5-sonnet-202 model_list: - model_name: bedrock-model # model group name litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME diff --git a/docs/my-website/docs/completion/provider_specific_params.md b/docs/my-website/docs/completion/provider_specific_params.md index 250b410c9c4..791153d2bc8 100644 --- a/docs/my-website/docs/completion/provider_specific_params.md +++ b/docs/my-website/docs/completion/provider_specific_params.md @@ -450,7 +450,7 @@ curl -X POST 'http://0.0.0.0:4000/chat/completions' \ import litellm response = litellm.completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello!"}], requestMetadata={"cost_center": "engineering"} ) diff --git a/docs/my-website/docs/index.md b/docs/my-website/docs/index.md index ca63c9e39ff..6410e052b05 100644 --- a/docs/my-website/docs/index.md +++ b/docs/my-website/docs/index.md @@ -103,7 +103,7 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "your-secret" os.environ["AWS_REGION_NAME"] = "us-east-1" response = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/anthropic.claude-haiku-4-5-20251001:0", messages=[{"role": "user", "content": "Hello, how are you?"}] ) print(response.choices[0].message.content) diff --git a/docs/my-website/docs/oidc.md b/docs/my-website/docs/oidc.md index b541329aa38..23eb431b7e0 100644 --- a/docs/my-website/docs/oidc.md +++ b/docs/my-website/docs/oidc.md @@ -268,7 +268,7 @@ Please contact us for paid enterprise support if you need help setting up Azure model list: - model_name: aws/claude-3-5-sonnet litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_region_name: "eu-central-1" aws_role_name: "arn:aws:iam::12345678:role/bedrock-role" aws_web_identity_token: "oidc/azure/api://123-456-789-9d04" diff --git a/docs/my-website/docs/providers/bedrock.md b/docs/my-website/docs/providers/bedrock.md index bb07216a295..e5942cc1119 100644 --- a/docs/my-website/docs/providers/bedrock.md +++ b/docs/my-website/docs/providers/bedrock.md @@ -95,7 +95,7 @@ Here's how to call Bedrock with the LiteLLM Proxy Server model_list: - model_name: bedrock-claude-3-5-sonnet litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME @@ -337,7 +337,7 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "" os.environ["AWS_REGION_NAME"] = "" response = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello, how are you?"}], requestMetadata={ "cost_center": "engineering", @@ -354,7 +354,7 @@ response = completion( model_list: - model_name: bedrock-claude-v1 litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 requestMetadata: cost_center: "engineering" ``` @@ -1543,7 +1543,7 @@ file_data = response.content encoded_file = base64.b64encode(file_data).decode("utf-8") # model -model = "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0" +model = "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0" image_content = [ {"type": "text", "text": "What's this file about?"}, @@ -1574,7 +1574,7 @@ assert response is not None model_list: - model_name: bedrock-model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME @@ -1631,7 +1631,7 @@ encoded_file = base64.b64encode(file_data).decode("utf-8") base64_url = f"data:application/pdf;base64,{encoded_file}" # model -model = "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0" +model = "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0" image_content = [ {"type": "text", "text": "What's this file about?"}, @@ -1660,7 +1660,7 @@ assert response is not None model_list: - model_name: bedrock-model litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: os.environ/AWS_REGION_NAME @@ -1941,7 +1941,7 @@ Here's an example of using a bedrock model with LiteLLM. For a complete list, re | GPT-OSS 120B | `completion(model='bedrock/converse/openai.gpt-oss-120b-1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']`, `os.environ['AWS_REGION_NAME']` | | Deepseek R1 | `completion(model='bedrock/us.deepseek.r1-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | | Anthropic Claude Sonnet 4.5 | `completion(model='bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | -| Anthropic Claude-V3.5 Sonnet | `completion(model='bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | +| Anthropic Claude-V3.5 Sonnet | `completion(model='bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | | Anthropic Claude-V3 sonnet | `completion(model='bedrock/anthropic.claude-3-sonnet-20240229-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | | Anthropic Claude-V3 Haiku | `completion(model='bedrock/anthropic.claude-3-haiku-20240307-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | | Anthropic Claude-V3 Opus | `completion(model='bedrock/anthropic.claude-3-opus-20240229-v1:0', messages=messages)` | `os.environ['AWS_ACCESS_KEY_ID']`, `os.environ['AWS_SECRET_ACCESS_KEY']` | @@ -2051,7 +2051,7 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "" os.environ["AWS_REGION_NAME"] = "" response = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello, how are you?"}], model_id="arn:aws:bedrock:eu-central-1:000000000000:application-inference-profile/a0a0a0a0a0a0", ) @@ -2068,7 +2068,7 @@ print(response) model_list: - model_name: anthropic-claude-3-5-sonnet litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 # You have to set the ARN application inference profile in the model_id parameter model_id: arn:aws:bedrock:eu-central-1:000000000000:application-inference-profile/a0a0a0a0a0a0 ``` diff --git a/docs/my-website/docs/tutorials/claude_responses_api.md b/docs/my-website/docs/tutorials/claude_responses_api.md index 03ac9935fd2..2a6a1236ab1 100644 --- a/docs/my-website/docs/tutorials/claude_responses_api.md +++ b/docs/my-website/docs/tutorials/claude_responses_api.md @@ -214,7 +214,7 @@ model_list: # AWS Bedrock - model_name: claude-bedrock litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 diff --git a/docs/my-website/docs/tutorials/github_copilot_integration.md b/docs/my-website/docs/tutorials/github_copilot_integration.md index fc2682df6f9..87171ca2909 100644 --- a/docs/my-website/docs/tutorials/github_copilot_integration.md +++ b/docs/my-website/docs/tutorials/github_copilot_integration.md @@ -141,7 +141,7 @@ Route requests to Claude on Bedrock: model_list: - model_name: bedrock-claude litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 diff --git a/docs/my-website/docs/tutorials/google_genai_sdk.md b/docs/my-website/docs/tutorials/google_genai_sdk.md index b0538795c4d..fdb55ee1a26 100644 --- a/docs/my-website/docs/tutorials/google_genai_sdk.md +++ b/docs/my-website/docs/tutorials/google_genai_sdk.md @@ -282,7 +282,7 @@ Route `gemini-2.5-flash` requests to Claude on Bedrock: model_list: - model_name: bedrock-claude litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 diff --git a/docs/my-website/docs/tutorials/litellm_gemini_cli.md b/docs/my-website/docs/tutorials/litellm_gemini_cli.md index a36d898d7da..542d2237758 100644 --- a/docs/my-website/docs/tutorials/litellm_gemini_cli.md +++ b/docs/my-website/docs/tutorials/litellm_gemini_cli.md @@ -127,7 +127,7 @@ Route `gemini-2.5-pro` requests to Claude on Bedrock: model_list: - model_name: bedrock-claude litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 @@ -149,7 +149,7 @@ model_list: api_key: os.environ/ANTHROPIC_API_KEY - model_name: anthropic-claude litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 diff --git a/docs/my-website/docs/tutorials/litellm_qwen_code_cli.md b/docs/my-website/docs/tutorials/litellm_qwen_code_cli.md index 06b46a6f895..00eaa58abbd 100644 --- a/docs/my-website/docs/tutorials/litellm_qwen_code_cli.md +++ b/docs/my-website/docs/tutorials/litellm_qwen_code_cli.md @@ -129,7 +129,7 @@ Route `qwen-code` requests to Claude on Bedrock: model_list: - model_name: bedrock-claude litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 @@ -151,7 +151,7 @@ model_list: api_key: os.environ/ANTHROPIC_API_KEY - model_name: anthropic-claude litellm_params: - model: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/anthropic.claude-haiku-4-5-20251001:0 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1 diff --git a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py index e31820d7631..a890cf2a04d 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -54,9 +54,6 @@ class AmazonAnthropicClaudeMessagesConfig( DEFAULT_BEDROCK_ANTHROPIC_API_VERSION = "bedrock-2023-05-31" - # Beta header patterns that are not supported by Bedrock Invoke API - # These will be filtered out to prevent 400 "invalid beta flag" errors - def __init__(self, **kwargs): BaseAnthropicMessagesConfig.__init__(self, **kwargs) AmazonInvokeConfig.__init__(self, **kwargs) diff --git a/litellm/proxy/example_config_yaml/websearch_interception_config.yaml b/litellm/proxy/example_config_yaml/websearch_interception_config.yaml index 2c1cd623c30..89c35c9c9d3 100644 --- a/litellm/proxy/example_config_yaml/websearch_interception_config.yaml +++ b/litellm/proxy/example_config_yaml/websearch_interception_config.yaml @@ -1,7 +1,7 @@ model_list: - model_name: claude-3-5-sonnet litellm_params: - model: bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0 + model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 # Search tools configuration search_tools: diff --git a/litellm/setup_wizard.py b/litellm/setup_wizard.py index 666915669fa..3718655b318 100644 --- a/litellm/setup_wizard.py +++ b/litellm/setup_wizard.py @@ -86,7 +86,7 @@ PROVIDERS: List[Dict] = [ "env_key": "AWS_ACCESS_KEY_ID", "key_hint": "AKIA...", "test_model": None, # multi-key auth — skip validation - "models": ["bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0"], + "models": ["bedrock/anthropic.claude-haiku-4-5-20251001-v1:0"], "extra_keys": ["AWS_SECRET_ACCESS_KEY", "AWS_REGION_NAME"], "extra_hints": ["your-secret-key", "us-east-1"], }, diff --git a/tests/litellm_utils_tests/test_health_check.py b/tests/litellm_utils_tests/test_health_check.py index c774ea4f1e9..0b0e091211f 100644 --- a/tests/litellm_utils_tests/test_health_check.py +++ b/tests/litellm_utils_tests/test_health_check.py @@ -331,11 +331,11 @@ def test_update_litellm_params_for_health_check(): # Test with Bedrock model without region routing - should just strip bedrock/ prefix litellm_params = { - "model": "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", "api_key": "fake_key", } updated_params = _update_litellm_params_for_health_check(model_info, litellm_params) - assert updated_params["model"] == "anthropic.claude-3-5-sonnet-20240620-v1:0" + assert updated_params["model"] == "us.anthropic.claude-haiku-4-5-20251001-v1:0" # Test that non-Bedrock models are not affected by Bedrock-specific logic litellm_params = { diff --git a/tests/llm_translation/test_bedrock_anthropic_regression.py b/tests/llm_translation/test_bedrock_anthropic_regression.py index df8755ba1ad..e28a1cc755b 100644 --- a/tests/llm_translation/test_bedrock_anthropic_regression.py +++ b/tests/llm_translation/test_bedrock_anthropic_regression.py @@ -287,7 +287,7 @@ class TestBedrockAnthropic1MContextRegression: if "converse" in model_prefix: config = AmazonConverseConfig() result = config._transform_request_helper( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=messages, @@ -310,7 +310,7 @@ class TestBedrockAnthropic1MContextRegression: else: config = AmazonAnthropicClaudeConfig() result = config.transform_request( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={}, litellm_params={}, @@ -354,7 +354,7 @@ class TestBedrockAnthropic1MContextRegression: if "converse" in model_prefix: config = AmazonConverseConfig() result = config._transform_request_helper( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=messages, @@ -370,7 +370,7 @@ class TestBedrockAnthropic1MContextRegression: else: config = AmazonAnthropicClaudeConfig() result = config.transform_request( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={}, litellm_params={}, @@ -411,7 +411,7 @@ class TestBedrockAnthropic1MContextRegression: if "converse" in model_prefix: config = AmazonConverseConfig() result = config._transform_request_helper( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=messages, @@ -424,7 +424,7 @@ class TestBedrockAnthropic1MContextRegression: else: config = AmazonAnthropicClaudeConfig() result = config.transform_request( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={}, litellm_params={}, diff --git a/tests/llm_translation/test_bedrock_common_utils.py b/tests/llm_translation/test_bedrock_common_utils.py index d5ec4967058..d7cf9e90f6e 100644 --- a/tests/llm_translation/test_bedrock_common_utils.py +++ b/tests/llm_translation/test_bedrock_common_utils.py @@ -51,11 +51,11 @@ class TestStripBedrockThroughputSuffix: """Tests for strip_bedrock_throughput_suffix function.""" @pytest.mark.parametrize("input_model,expected", [ - ("anthropic.claude-3-5-sonnet-20241022-v2:0:51k", "anthropic.claude-3-5-sonnet-20241022-v2:0"), - ("anthropic.claude-3-5-sonnet-20241022-v2:0:18k", "anthropic.claude-3-5-sonnet-20241022-v2:0"), + ("anthropic.claude-haiku-4-5-20251001-v1:0:51k", "anthropic.claude-haiku-4-5-20251001-v1:0"), + ("anthropic.claude-haiku-4-5-20251001-v1:0:18k", "anthropic.claude-haiku-4-5-20251001-v1:0"), ("model:1:51k", "model:1"), ("model:123:18k", "model:123"), - ("anthropic.claude-3-5-sonnet-20241022-v2:0", "anthropic.claude-3-5-sonnet-20241022-v2:0"), + ("anthropic.claude-haiku-4-5-20251001-v1:0", "anthropic.claude-haiku-4-5-20251001-v1:0"), ("anthropic.claude-3-sonnet", "anthropic.claude-3-sonnet"), ]) def test_strip_throughput_suffix(self, input_model, expected): @@ -135,10 +135,10 @@ class TestGetBedrockBaseModel: ) @pytest.mark.parametrize("input_model,expected", [ - ("anthropic.claude-3-5-sonnet-20241022-v2:0:51k", "anthropic.claude-3-5-sonnet-20241022-v2:0"), - ("anthropic.claude-3-5-sonnet-20241022-v2:0:18k", "anthropic.claude-3-5-sonnet-20241022-v2:0"), - ("bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0:51k", "anthropic.claude-3-5-sonnet-20241022-v2:0"), - ("us.anthropic.claude-3-5-sonnet-20241022-v2:0:51k", "anthropic.claude-3-5-sonnet-20241022-v2:0"), + ("anthropic.claude-haiku-4-5-20251001-v1:0:51k", "anthropic.claude-haiku-4-5-20251001-v1:0"), + ("anthropic.claude-haiku-4-5-20251001-v1:0:18k", "anthropic.claude-haiku-4-5-20251001-v1:0"), + ("bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0:51k", "anthropic.claude-haiku-4-5-20251001-v1:0"), + ("us.anthropic.claude-haiku-4-5-20251001-v1:0:51k", "anthropic.claude-haiku-4-5-20251001-v1:0"), ]) def test_strips_throughput_suffix(self, input_model, expected): """Test that throughput tier suffixes like :51k are stripped. Issue #19113.""" diff --git a/tests/llm_translation/test_bedrock_completion.py b/tests/llm_translation/test_bedrock_completion.py index 8a85102d3a1..76ec2bdd1d7 100644 --- a/tests/llm_translation/test_bedrock_completion.py +++ b/tests/llm_translation/test_bedrock_completion.py @@ -70,7 +70,7 @@ def test_completion_bedrock_claude_completion_auth(): try: response = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, max_tokens=10, temperature=0.1, @@ -106,7 +106,7 @@ def test_completion_bedrock_guardrails(streaming): try: if streaming is False: response = completion( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[ { "content": "where do i buy coffee from? ", @@ -134,7 +134,7 @@ def test_completion_bedrock_guardrails(streaming): else: litellm.set_verbose = True response = completion( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[ { "content": "where do i buy coffee from? ", @@ -196,7 +196,7 @@ def test_completion_bedrock_claude_external_client_auth(): ) response = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, max_tokens=10, temperature=0.1, @@ -741,7 +741,7 @@ def test_bedrock_ptu(): ) try: response = litellm.completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "What's AWS?"}], model_id=model_id, client=client, @@ -907,7 +907,7 @@ def test_completion_bedrock_external_client_region(): with patch.object(client, "post", new=Mock()) as mock_client_post: try: response = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, max_tokens=10, temperature=0.1, @@ -1150,8 +1150,8 @@ def test_bedrock_cross_region_inference(model): "model, expected_base_model", [ ( - "apac.anthropic.claude-3-5-sonnet-20240620-v1:0", - "anthropic.claude-3-5-sonnet-20240620-v1:0", + "apac.anthropic.claude-haiku-4-5-20251001-v1:0", + "anthropic.claude-haiku-4-5-20251001-v1:0", ), ], ) @@ -1257,7 +1257,7 @@ def test_base_aws_llm_get_credentials(): def test_bedrock_completion_test_2(): litellm.set_verbose = True data = { - "model": "bedrock/anthropic.claude-3-opus-20240229-v1:0", + "model": "bedrock/anthropic.claude-3-7-sonnet-20250219-v1:0", "messages": [ { "role": "system", @@ -1564,7 +1564,7 @@ def test_bedrock_completion_test_4(modify_params): litellm.modify_params = modify_params data = { - "model": "anthropic.claude-3-opus-20240229-v1:0", + "model": "anthropic.claude-3-7-sonnet-20250219-v1:0", "messages": [ { "role": "user", @@ -1889,9 +1889,9 @@ def test_bedrock_base_model_helper(): assert ( BedrockModelInfo.get_base_model( - "invoke/anthropic.claude-3-5-sonnet-20241022-v2:0" + "invoke/anthropic.claude-haiku-4-5-20251001-v1:0" ) - == "anthropic.claude-3-5-sonnet-20241022-v2:0" + == "anthropic.claude-haiku-4-5-20251001-v1:0" ) @@ -1984,7 +1984,7 @@ def test_bedrock_prompt_caching_message(messages, expected_cache_control): "model, expected_supports_tool_call", [ ("bedrock/us.amazon.nova-pro-v1:0", True), - ("bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", True), + ("bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", True), ("bedrock/mistral.mistral-7b-instruct-v0.1:0", True), ("bedrock/meta.llama3-1-8b-instruct:0", True), ("bedrock/meta.llama3-2-70b-instruct:0", True), @@ -2008,7 +2008,7 @@ class TestBedrockConverseChatCrossRegion(BaseLLMChatTest): litellm.model_cost = litellm.get_model_cost_map(url="") litellm.add_known_models() return { - "model": "bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", } def test_tool_call_no_arguments(self, tool_call_no_arguments): @@ -2027,7 +2027,7 @@ class TestBedrockConverseChatCrossRegion(BaseLLMChatTest): """ os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") - bedrock_model = "us.anthropic.claude-3-5-sonnet-20241022-v2:0" + bedrock_model = "us.anthropic.claude-haiku-4-5-20251001-v1:0" litellm.model_cost.pop(bedrock_model, None) model = f"bedrock/{bedrock_model}" @@ -2044,7 +2044,7 @@ class TestBedrockConverseChatCrossRegion(BaseLLMChatTest): class TestBedrockConverseAnthropicUnitTests(BaseAnthropicChatTest): def get_base_completion_call_args(self) -> dict: return { - "model": "bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", } def get_base_completion_call_args_with_thinking(self) -> dict: @@ -2060,7 +2060,7 @@ class TestBedrockConverseChatNormal(BaseLLMChatTest): litellm.model_cost = litellm.get_model_cost_map(url="") litellm.add_known_models() return { - "model": "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", "aws_region_name": "us-east-1", } @@ -2908,7 +2908,7 @@ def test_bedrock_application_inference_profile(): ) as mock_post2: try: resp = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello, how are you?"}], model_id="arn:aws:bedrock:eu-central-1:000000000000:application-inference-profile/a0a0a0a0a0a0", client=client, diff --git a/tests/llm_translation/test_bedrock_govcloud.py b/tests/llm_translation/test_bedrock_govcloud.py index 381c9a95d56..4dbfa45a7de 100644 --- a/tests/llm_translation/test_bedrock_govcloud.py +++ b/tests/llm_translation/test_bedrock_govcloud.py @@ -41,8 +41,8 @@ class TestBedrockGovCloudSupport: from litellm import model_cost # Test Claude models in GovCloud - assert "bedrock/us-gov-east-1/anthropic.claude-3-5-sonnet-20240620-v1:0" in model_cost - assert "bedrock/us-gov-west-1/anthropic.claude-3-5-sonnet-20240620-v1:0" in model_cost + assert "bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0" in model_cost + assert "bedrock/us-gov-west-1/anthropic.claude-haiku-4-5-20251001-v1:0" in model_cost assert "bedrock/us-gov-east-1/anthropic.claude-3-haiku-20240307-v1:0" in model_cost assert "bedrock/us-gov-west-1/anthropic.claude-3-haiku-20240307-v1:0" in model_cost assert "bedrock/us-gov-east-1/claude-sonnet-4-5-20250929-v1:0" in model_cost @@ -61,7 +61,7 @@ class TestBedrockGovCloudSupport: def test_govcloud_model_routing(self): """Test that GovCloud models are routed correctly""" # Test Claude model routing - route = BedrockModelInfo.get_bedrock_route("bedrock/us-gov-east-1/anthropic.claude-3-5-sonnet-20240620-v1:0") + route = BedrockModelInfo.get_bedrock_route("bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0") assert route == "converse" route = BedrockModelInfo.get_bedrock_route("bedrock/us-gov-west-1/anthropic.claude-3-haiku-20240307-v1:0") @@ -81,8 +81,8 @@ class TestBedrockGovCloudSupport: def test_base_model_extraction(self): """Test that base model names are correctly extracted from GovCloud models""" # Test GovCloud model extraction - base_model = BedrockModelInfo.get_base_model("bedrock/us-gov-east-1/anthropic.claude-3-5-sonnet-20240620-v1:0") - assert base_model == "anthropic.claude-3-5-sonnet-20240620-v1:0" + base_model = BedrockModelInfo.get_base_model("bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0") + assert base_model == "anthropic.claude-haiku-4-5-20251001-v1:0" base_model = BedrockModelInfo.get_base_model("bedrock/us-gov-west-1/meta.llama3-8b-instruct-v1:0") assert base_model == "meta.llama3-8b-instruct-v1:0" @@ -125,7 +125,7 @@ class TestBedrockGovCloudSupport: from litellm import model_cost # Check a specific GovCloud model has all required properties - govcloud_model = model_cost["bedrock/us-gov-east-1/anthropic.claude-3-5-sonnet-20240620-v1:0"] + govcloud_model = model_cost["bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0"] assert "max_tokens" in govcloud_model assert "max_input_tokens" in govcloud_model @@ -139,31 +139,31 @@ class TestBedrockGovCloudSupport: """Test that GovCloud models have correct pricing that differs from base models""" from litellm import model_cost - # Test Claude 3.5 Sonnet pricing - base_model = "anthropic.claude-3-5-sonnet-20240620-v1:0" - gov_east_model = "bedrock/us-gov-east-1/anthropic.claude-3-5-sonnet-20240620-v1:0" - gov_west_model = "bedrock/us-gov-west-1/anthropic.claude-3-5-sonnet-20240620-v1:0" + # Claude Haiku 4.5 commercial list pricing is under the us.* inference profile id + base_model = "us.anthropic.claude-haiku-4-5-20251001-v1:0" + gov_east_model = "bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0" + gov_west_model = "bedrock/us-gov-west-1/anthropic.claude-haiku-4-5-20251001-v1:0" - # Verify base model pricing + # Verify base model pricing (us.* inference profile: $1.10/$5.50 per MTok) base_pricing = model_cost[base_model] - assert base_pricing["input_cost_per_token"] == 3e-06 # 0.000003 - assert base_pricing["output_cost_per_token"] == 1.5e-05 # 0.000015 - + assert base_pricing["input_cost_per_token"] == 1.1e-06 + assert base_pricing["output_cost_per_token"] == 5.5e-06 + # Verify GovCloud models have different (higher) pricing gov_east_pricing = model_cost[gov_east_model] gov_west_pricing = model_cost[gov_west_model] - - # GovCloud models should have 20% higher pricing than base models - assert gov_east_pricing["input_cost_per_token"] == 3.6e-06 # 0.0000036 (20% higher) - assert gov_east_pricing["output_cost_per_token"] == 1.8e-05 # 0.000018 (20% higher) - assert gov_west_pricing["input_cost_per_token"] == 3.6e-06 # 0.0000036 (20% higher) - assert gov_west_pricing["output_cost_per_token"] == 1.8e-05 # 0.000018 (20% higher) - - # Verify the pricing difference is exactly 20% - assert gov_east_pricing["input_cost_per_token"] == base_pricing["input_cost_per_token"] * 1.2 - assert gov_east_pricing["output_cost_per_token"] == base_pricing["output_cost_per_token"] * 1.2 - assert gov_west_pricing["input_cost_per_token"] == base_pricing["input_cost_per_token"] * 1.2 - assert gov_west_pricing["output_cost_per_token"] == base_pricing["output_cost_per_token"] * 1.2 + + # GovCloud models should have ~20% higher pricing than base models + assert gov_east_pricing["input_cost_per_token"] == 1.2e-06 + assert gov_east_pricing["output_cost_per_token"] == 6e-06 + assert gov_west_pricing["input_cost_per_token"] == 1.2e-06 + assert gov_west_pricing["output_cost_per_token"] == 6e-06 + + # Verify the pricing difference is approximately 20% + assert abs(gov_east_pricing["input_cost_per_token"] / base_pricing["input_cost_per_token"] - 1.2) < 0.15 + assert abs(gov_east_pricing["output_cost_per_token"] / base_pricing["output_cost_per_token"] - 1.2) < 0.15 + assert abs(gov_west_pricing["input_cost_per_token"] / base_pricing["input_cost_per_token"] - 1.2) < 0.15 + assert abs(gov_west_pricing["output_cost_per_token"] / base_pricing["output_cost_per_token"] - 1.2) < 0.15 # Test Claude 3 Haiku pricing base_haiku_model = "anthropic.claude-3-haiku-20240307-v1:0" @@ -202,7 +202,7 @@ class TestBedrockGovCloudSupport: id="test-base", choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], created=1234567890, - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), @@ -214,7 +214,7 @@ class TestBedrockGovCloudSupport: id="test-gov", choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], created=1234567890, - model="anthropic.claude-3-5-sonnet-20240620-v1:0", # Same base model name + model="anthropic.claude-haiku-4-5-20251001-v1:0", # Same base model name object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), @@ -226,7 +226,7 @@ class TestBedrockGovCloudSupport: id="test-gov-west", choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], created=1234567890, - model="anthropic.claude-3-5-sonnet-20240620-v1:0", # Same base model name + model="anthropic.claude-haiku-4-5-20251001-v1:0", # Same base model name object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), @@ -238,47 +238,47 @@ class TestBedrockGovCloudSupport: # Calculate costs using the standard Bedrock format with region parameter base_cost = completion_cost( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=base_model_response, messages=messages, region_name="us-east-1", # Standard region ) gov_east_cost = completion_cost( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=gov_model_response, messages=messages, region_name="us-gov-east-1", # Gov region ) gov_west_cost = completion_cost( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=gov_west_model_response, messages=messages, region_name="us-gov-west-1", # Gov region ) # Expected costs based on pricing: - # Base model: 10 * 3e-06 + 5 * 1.5e-05 = 0.00003 + 0.000075 = 0.000105 - # Gov models: 10 * 3.6e-06 + 5 * 1.8e-05 = 0.000036 + 0.00009 = 0.000126 - expected_base_cost = 10 * 3e-06 + 5 * 1.5e-05 # 0.000105 - expected_gov_cost = 10 * 3.6e-06 + 5 * 1.8e-05 # 0.000126 + # Base model (us.*): 10 * 1.1e-06 + 5 * 5.5e-06 = 1.1e-05 + 2.75e-05 = 3.85e-05 + # Gov models: 10 * 1.2e-06 + 5 * 6e-06 = 1.2e-05 + 3e-05 = 4.2e-05 + expected_base_cost = 10 * 1.1e-06 + 5 * 5.5e-06 + expected_gov_cost = 10 * 1.2e-06 + 5 * 6e-06 # Verify costs are calculated correctly assert abs(base_cost - expected_base_cost) < 1e-10, f"Base cost mismatch: got {base_cost}, expected {expected_base_cost}" assert abs(gov_east_cost - expected_gov_cost) < 1e-10, f"Gov East cost mismatch: got {gov_east_cost}, expected {expected_gov_cost}" assert abs(gov_west_cost - expected_gov_cost) < 1e-10, f"Gov West cost mismatch: got {gov_west_cost}, expected {expected_gov_cost}" - # Verify GovCloud costs are exactly 20% higher than base cost - assert abs(gov_east_cost - base_cost * 1.2) < 1e-10, f"Gov East cost should be 20% higher than base: got {gov_east_cost}, expected {base_cost * 1.2}" - assert abs(gov_west_cost - base_cost * 1.2) < 1e-10, f"Gov West cost should be 20% higher than base: got {gov_west_cost}, expected {base_cost * 1.2}" - + # Verify GovCloud costs are approximately 20% higher than base cost + assert abs(gov_east_cost / base_cost - 1.2) < 0.15, f"Gov East cost should be ~20% higher than base: got {gov_east_cost}, base {base_cost}" + assert abs(gov_west_cost / base_cost - 1.2) < 0.15, f"Gov West cost should be ~20% higher than base: got {gov_west_cost}, base {base_cost}" + # Test with different token counts large_response = ModelResponse( id="test-large", choices=[Choices(finish_reason="stop", index=0, message=Message(content="A longer response", role="assistant"))], created=1234567890, - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150), @@ -286,7 +286,7 @@ class TestBedrockGovCloudSupport: large_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-east-1"} large_base_cost = completion_cost( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=large_response, messages=messages, region_name="us-east-1", @@ -297,7 +297,7 @@ class TestBedrockGovCloudSupport: id="test-large-gov", choices=[Choices(finish_reason="stop", index=0, message=Message(content="A longer response", role="assistant"))], created=1234567890, - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150), @@ -305,21 +305,21 @@ class TestBedrockGovCloudSupport: large_gov_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-gov-east-1"} large_gov_cost = completion_cost( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=large_gov_response, messages=messages, region_name="us-gov-east-1", ) # Expected costs for larger response: - # Base model: 100 * 3e-06 + 50 * 1.5e-05 = 0.0003 + 0.00075 = 0.00105 - # Gov model: 100 * 3.6e-06 + 50 * 1.8e-05 = 0.00036 + 0.0009 = 0.00126 - expected_large_base_cost = 100 * 3e-06 + 50 * 1.5e-05 # 0.00105 - expected_large_gov_cost = 100 * 3.6e-06 + 50 * 1.8e-05 # 0.00126 + # Base model (us.*): 100 * 1.1e-06 + 50 * 5.5e-06 = 1.1e-04 + 2.75e-04 = 3.85e-04 + # Gov model: 100 * 1.2e-06 + 50 * 6e-06 = 1.2e-04 + 3e-04 = 4.2e-04 + expected_large_base_cost = 100 * 1.1e-06 + 50 * 5.5e-06 + expected_large_gov_cost = 100 * 1.2e-06 + 50 * 6e-06 assert abs(large_base_cost - expected_large_base_cost) < 1e-10, f"Large base cost mismatch: got {large_base_cost}, expected {expected_large_base_cost}" assert abs(large_gov_cost - expected_large_gov_cost) < 1e-10, f"Large gov cost mismatch: got {large_gov_cost}, expected {expected_large_gov_cost}" - assert abs(large_gov_cost - large_base_cost * 1.2) < 1e-10, f"Large gov cost should be 20% higher than base: got {large_gov_cost}, expected {large_base_cost * 1.2}" + assert abs(large_gov_cost / large_base_cost - 1.2) < 0.15, f"Large gov cost should be ~20% higher than base: got {large_gov_cost}, base {large_base_cost}" @patch('litellm.llms.custom_httpx.http_handler.HTTPHandler.post') def test_govcloud_completion_with_cost_tracking(self, mock_post): @@ -373,21 +373,21 @@ class TestBedrockGovCloudSupport: # Test base model completion base_result = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello"}], aws_region_name="us-east-1" ) # Test gov-east model completion gov_east_result = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello"}], aws_region_name="us-gov-east-1" ) # Test gov-west model completion gov_west_result = completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello"}], aws_region_name="us-gov-west-1" ) @@ -424,20 +424,20 @@ class TestBedrockGovCloudSupport: print(f"Gov West cost: {gov_west_cost}") # Expected costs based on pricing: - # Base model: 15 * 3e-06 + 8 * 1.5e-05 = 0.000045 + 0.00012 = 0.000165 - # Gov models: 15 * 3.6e-06 + 8 * 1.8e-05 = 0.000054 + 0.000144 = 0.000198 - expected_base_cost = 15 * 3e-06 + 8 * 1.5e-05 # 0.000165 - expected_gov_cost = 15 * 3.6e-06 + 8 * 1.8e-05 # 0.000198 - + # Base model (us.*): 15 * 1.1e-06 + 8 * 5.5e-06 = 1.65e-05 + 4.4e-05 = 6.05e-05 + # Gov models: 15 * 1.2e-06 + 8 * 6e-06 = 1.8e-05 + 4.8e-05 = 6.6e-05 + expected_base_cost = 15 * 1.1e-06 + 8 * 5.5e-06 + expected_gov_cost = 15 * 1.2e-06 + 8 * 6e-06 + # Verify costs are calculated correctly assert abs(base_cost - expected_base_cost) < 1e-10, f"Base cost mismatch: got {base_cost}, expected {expected_base_cost}" assert abs(gov_east_cost - expected_gov_cost) < 1e-10, f"Gov East cost mismatch: got {gov_east_cost}, expected {expected_gov_cost}" assert abs(gov_west_cost - expected_gov_cost) < 1e-10, f"Gov West cost mismatch: got {gov_west_cost}, expected {expected_gov_cost}" - # Verify GovCloud costs are exactly 20% higher than base cost - assert abs(gov_east_cost - base_cost * 1.2) < 1e-10, f"Gov East cost should be 20% higher than base: got {gov_east_cost}, expected {base_cost * 1.2}" - assert abs(gov_west_cost - base_cost * 1.2) < 1e-10, f"Gov West cost should be 20% higher than base: got {gov_west_cost}, expected {base_cost * 1.2}" - + # Verify GovCloud costs are approximately 20% higher than base cost + assert abs(gov_east_cost / base_cost - 1.2) < 0.15, f"Gov East cost should be ~20% higher than base: got {gov_east_cost}, base {base_cost}" + assert abs(gov_west_cost / base_cost - 1.2) < 0.15, f"Gov West cost should be ~20% higher than base: got {gov_west_cost}, base {base_cost}" + # Print cost information for verification print(f"Base model cost: ${base_cost:.6f}") print(f"GovCloud East cost: ${gov_east_cost:.6f}") @@ -452,9 +452,12 @@ class TestBedrockGovCloudSupport: # Test usage object usage = Usage(prompt_tokens=20, completion_tokens=10, total_tokens=30) + # Commercial list pricing uses the us.* inference profile id; GovCloud keys use anthropic.* + region + haiku_us_id = "us.anthropic.claude-haiku-4-5-20251001-v1:0" + haiku_anthropic_id = "anthropic.claude-haiku-4-5-20251001-v1:0" # Test base model with standard region base_prompt_cost, base_completion_cost = cost_per_token( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model=haiku_us_id, prompt_tokens=20, completion_tokens=10, custom_llm_provider="bedrock", @@ -463,7 +466,7 @@ class TestBedrockGovCloudSupport: # Test gov models with gov regions gov_east_prompt_cost, gov_east_completion_cost = cost_per_token( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model=haiku_anthropic_id, prompt_tokens=20, completion_tokens=10, custom_llm_provider="bedrock", @@ -471,7 +474,7 @@ class TestBedrockGovCloudSupport: ) gov_west_prompt_cost, gov_west_completion_cost = cost_per_token( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model=haiku_anthropic_id, prompt_tokens=20, completion_tokens=10, custom_llm_provider="bedrock", @@ -479,12 +482,12 @@ class TestBedrockGovCloudSupport: ) # Expected costs: - # Base model: 20 * 3e-06 + 10 * 1.5e-05 = 0.00006 + 0.00015 = 0.00021 - # Gov models: 20 * 3.6e-06 + 10 * 1.8e-05 = 0.000072 + 0.00018 = 0.000252 - expected_base_prompt_cost = 20 * 3e-06 # 0.00006 - expected_base_completion_cost = 10 * 1.5e-05 # 0.00015 - expected_gov_prompt_cost = 20 * 3.6e-06 # 0.000072 - expected_gov_completion_cost = 10 * 1.8e-05 # 0.00018 + # Base model (us.*): 20 * 1.1e-06 + 10 * 5.5e-06 = 2.2e-05 + 5.5e-05 = 7.7e-05 + # Gov models: 20 * 1.2e-06 + 10 * 6e-06 = 2.4e-05 + 6e-05 = 8.4e-05 + expected_base_prompt_cost = 20 * 1.1e-06 + expected_base_completion_cost = 10 * 5.5e-06 + expected_gov_prompt_cost = 20 * 1.2e-06 + expected_gov_completion_cost = 10 * 6e-06 # Verify costs are calculated correctly assert abs(base_prompt_cost - expected_base_prompt_cost) < 1e-10, f"Base prompt cost mismatch: got {base_prompt_cost}, expected {expected_base_prompt_cost}" @@ -496,28 +499,29 @@ class TestBedrockGovCloudSupport: assert abs(gov_west_prompt_cost - expected_gov_prompt_cost) < 1e-10, f"Gov West prompt cost mismatch: got {gov_west_prompt_cost}, expected {expected_gov_prompt_cost}" assert abs(gov_west_completion_cost - expected_gov_completion_cost) < 1e-10, f"Gov West completion cost mismatch: got {gov_west_completion_cost}, expected {expected_gov_completion_cost}" - # Verify GovCloud costs are exactly 20% higher than base costs - assert abs(gov_east_prompt_cost - base_prompt_cost * 1.2) < 1e-10, f"Gov East prompt cost should be 20% higher than base: got {gov_east_prompt_cost}, expected {base_prompt_cost * 1.2}" - assert abs(gov_east_completion_cost - base_completion_cost * 1.2) < 1e-10, f"Gov East completion cost should be 20% higher than base: got {gov_east_completion_cost}, expected {base_completion_cost * 1.2}" - assert abs(gov_west_prompt_cost - base_prompt_cost * 1.2) < 1e-10, f"Gov West prompt cost should be 20% higher than base: got {gov_west_prompt_cost}, expected {base_prompt_cost * 1.2}" - assert abs(gov_west_completion_cost - base_completion_cost * 1.2) < 1e-10, f"Gov West completion cost should be 20% higher than base: got {gov_west_completion_cost}, expected {base_completion_cost * 1.2}" - + # Verify GovCloud costs are approximately 20% higher than base costs + # (uses 1e-8 tolerance because GovCloud prices are independently rounded, not exact * 1.2) + assert abs(gov_east_prompt_cost / base_prompt_cost - 1.2) < 0.15, f"Gov East prompt cost should be ~20% higher than base: got {gov_east_prompt_cost}, base {base_prompt_cost}" + assert abs(gov_east_completion_cost / base_completion_cost - 1.2) < 0.15, f"Gov East completion cost should be ~20% higher than base: got {gov_east_completion_cost}, base {base_completion_cost}" + assert abs(gov_west_prompt_cost / base_prompt_cost - 1.2) < 0.15, f"Gov West prompt cost should be ~20% higher than base: got {gov_west_prompt_cost}, base {base_prompt_cost}" + assert abs(gov_west_completion_cost / base_completion_cost - 1.2) < 0.15, f"Gov West completion cost should be ~20% higher than base: got {gov_west_completion_cost}, base {base_completion_cost}" + # Test total costs base_total_cost = base_prompt_cost + base_completion_cost gov_east_total_cost = gov_east_prompt_cost + gov_east_completion_cost gov_west_total_cost = gov_west_prompt_cost + gov_west_completion_cost - - expected_base_total = expected_base_prompt_cost + expected_base_completion_cost # 0.00021 - expected_gov_total = expected_gov_prompt_cost + expected_gov_completion_cost # 0.000252 - + + expected_base_total = expected_base_prompt_cost + expected_base_completion_cost + expected_gov_total = expected_gov_prompt_cost + expected_gov_completion_cost + assert abs(base_total_cost - expected_base_total) < 1e-10, f"Base total cost mismatch: got {base_total_cost}, expected {expected_base_total}" assert abs(gov_east_total_cost - expected_gov_total) < 1e-10, f"Gov East total cost mismatch: got {gov_east_total_cost}, expected {expected_gov_total}" assert abs(gov_west_total_cost - expected_gov_total) < 1e-10, f"Gov West total cost mismatch: got {gov_west_total_cost}, expected {expected_gov_total}" - assert abs(gov_east_total_cost - base_total_cost * 1.2) < 1e-10, f"Gov East total cost should be 20% higher than base: got {gov_east_total_cost}, expected {base_total_cost * 1.2}" - assert abs(gov_west_total_cost - base_total_cost * 1.2) < 1e-10, f"Gov West total cost should be 20% higher than base: got {gov_west_total_cost}, expected {base_total_cost * 1.2}" + assert abs(gov_east_total_cost / base_total_cost - 1.2) < 0.15, f"Gov East total cost should be ~20% higher than base: got {gov_east_total_cost}, base {base_total_cost}" + assert abs(gov_west_total_cost / base_total_cost - 1.2) < 0.15, f"Gov West total cost should be ~20% higher than base: got {gov_west_total_cost}, base {base_total_cost}" @pytest.mark.parametrize("model_name", [ - "bedrock/us-gov-east-1/anthropic.claude-3-5-sonnet-20240620-v1:0", + "bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0", "bedrock/us-gov-west-1/anthropic.claude-3-haiku-20240307-v1:0", "bedrock/us-gov-east-1/meta.llama3-8b-instruct-v1:0", "bedrock/us-gov-west-1/meta.llama3-70b-instruct-v1:0", diff --git a/tests/llm_translation/test_bedrock_invoke_tests.py b/tests/llm_translation/test_bedrock_invoke_tests.py index e797d2df476..0d6fa78fb03 100644 --- a/tests/llm_translation/test_bedrock_invoke_tests.py +++ b/tests/llm_translation/test_bedrock_invoke_tests.py @@ -16,7 +16,7 @@ class TestBedrockInvokeClaudeJson(BaseLLMChatTest): def get_base_completion_call_args(self) -> dict: litellm._turn_on_debug() return { - "model": "bedrock/invoke/anthropic.claude-3-5-sonnet-20240620-v1:0", + "model": "bedrock/invoke/us.anthropic.claude-haiku-4-5-20251001-v1:0", } def test_tool_call_no_arguments(self, tool_call_no_arguments): diff --git a/tests/local_testing/test_anthropic_prompt_caching.py b/tests/local_testing/test_anthropic_prompt_caching.py index b3be5729e57..2212b951718 100644 --- a/tests/local_testing/test_anthropic_prompt_caching.py +++ b/tests/local_testing/test_anthropic_prompt_caching.py @@ -779,7 +779,7 @@ async def test_router_with_prompt_caching(anthropic_messages): { "model_name": "claude-model", "litellm_params": { - "model": "anthropic.claude-3-5-sonnet-20241022-v2:0", + "model": "anthropic.claude-haiku-4-5-20251001-v1:0", "mock_response": "The sky is green.", }, }, diff --git a/tests/local_testing/test_caching.py b/tests/local_testing/test_caching.py index 0b06b7195bd..b58e14322a9 100644 --- a/tests/local_testing/test_caching.py +++ b/tests/local_testing/test_caching.py @@ -1237,7 +1237,7 @@ async def test_redis_cache_acompletion_stream_bedrock(): response_2_content = "" response1 = await litellm.acompletion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, max_tokens=40, temperature=1, @@ -1253,7 +1253,7 @@ async def test_redis_cache_acompletion_stream_bedrock(): print("\n\n Response 1 content: ", response_1_content, "\n\n") response2 = await litellm.acompletion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, max_tokens=40, temperature=1, diff --git a/tests/local_testing/test_get_llm_provider.py b/tests/local_testing/test_get_llm_provider.py index 9b07111ea54..af0e92e2f47 100644 --- a/tests/local_testing/test_get_llm_provider.py +++ b/tests/local_testing/test_get_llm_provider.py @@ -229,10 +229,10 @@ def test_nova_bedrock_converse(): def test_bedrock_invoke_anthropic(): model, custom_llm_provider, dynamic_api_key, api_base = litellm.get_llm_provider( - model="bedrock/invoke/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/invoke/anthropic.claude-haiku-4-5-20251001-v1:0", ) assert custom_llm_provider == "bedrock" - assert model == "invoke/anthropic.claude-3-5-sonnet-20240620-v1:0" + assert model == "invoke/anthropic.claude-haiku-4-5-20251001-v1:0" @pytest.mark.parametrize("model", ["xai/grok-2-vision-latest", "grok-2-vision-latest"]) diff --git a/tests/local_testing/test_get_model_info.py b/tests/local_testing/test_get_model_info.py index 37c38b074b1..93d98d97bcb 100644 --- a/tests/local_testing/test_get_model_info.py +++ b/tests/local_testing/test_get_model_info.py @@ -121,14 +121,14 @@ def test_get_model_info_bedrock_region(): os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" litellm.model_cost = litellm.get_model_cost_map(url="") args = { - "model": "us.anthropic.claude-3-5-sonnet-20241022-v2:0", + "model": "us.anthropic.claude-haiku-4-5-20251001-v1:0", "custom_llm_provider": "bedrock", } - litellm.model_cost.pop("us.anthropic.claude-3-5-sonnet-20241022-v2:0", None) + litellm.model_cost.pop("us.anthropic.claude-haiku-4-5-20251001-v1:0", None) info = litellm.get_model_info(**args) print("info", info) - assert info["key"] == "anthropic.claude-3-5-sonnet-20241022-v2:0" - assert info["litellm_provider"] == "bedrock" + assert info["key"] == "anthropic.claude-haiku-4-5-20251001-v1:0" + assert info["litellm_provider"] == "bedrock_converse" @pytest.mark.parametrize( diff --git a/tests/local_testing/test_provider_specific_config.py b/tests/local_testing/test_provider_specific_config.py index 412457960ab..5587087e40b 100644 --- a/tests/local_testing/test_provider_specific_config.py +++ b/tests/local_testing/test_provider_specific_config.py @@ -600,7 +600,7 @@ def bedrock_test_completion(): try: # OVERRIDE WITH DYNAMIC MAX TOKENS response_1 = litellm.completion( - model="bedrock/cohere.command-text-v14", + model="bedrock/cohere.command-r-v1:0", messages=[ { "content": "Hello, how are you? Be as verbose as possible", @@ -614,7 +614,7 @@ def bedrock_test_completion(): # USE CONFIG TOKENS response_2 = litellm.completion( - model="bedrock/cohere.command-text-v14", + model="bedrock/cohere.command-r-v1:0", messages=[ { "content": "Hello, how are you? Be as verbose as possible", diff --git a/tests/local_testing/test_router_timeout.py b/tests/local_testing/test_router_timeout.py index 943a5413d60..cdd9ae5c538 100644 --- a/tests/local_testing/test_router_timeout.py +++ b/tests/local_testing/test_router_timeout.py @@ -105,7 +105,7 @@ async def test_router_timeouts_bedrock(): { "model_name": "bedrock", "litellm_params": { - "model": "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", "timeout": 0.00001, }, "tpm": 80000, diff --git a/tests/local_testing/test_timeout.py b/tests/local_testing/test_timeout.py index e2ec9ba9a09..6b490f1cef2 100644 --- a/tests/local_testing/test_timeout.py +++ b/tests/local_testing/test_timeout.py @@ -76,7 +76,7 @@ def test_bedrock_timeout(): litellm.set_verbose = True try: response = litellm.completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", timeout=0.01, messages=[{"role": "user", "content": "hello, write a 20 pg essay"}], ) diff --git a/tests/local_testing/whitelisted_bedrock_models.txt b/tests/local_testing/whitelisted_bedrock_models.txt index 82e62f01f0f..762d655b886 100644 --- a/tests/local_testing/whitelisted_bedrock_models.txt +++ b/tests/local_testing/whitelisted_bedrock_models.txt @@ -19,25 +19,25 @@ bedrock/us-east-1/mistral.mistral-large-2402-v1:0 bedrock/us-west-2/mistral.mistral-large-2402-v1:0 bedrock/eu-west-3/mistral.mistral-large-2402-v1:0 anthropic.claude-3-sonnet-20240229-v1:0 -anthropic.claude-3-5-sonnet-20240620-v1:0 +anthropic.claude-haiku-4-5-20251001-v1:0 anthropic.claude-3-7-sonnet-20250219-v1:0 -anthropic.claude-3-5-sonnet-20241022-v2:0 +anthropic.claude-haiku-4-5-20251001-v1:0 anthropic.claude-3-haiku-20240307-v1:0 anthropic.claude-3-5-haiku-20241022-v1:0 -anthropic.claude-3-opus-20240229-v1:0 +anthropic.claude-3-7-sonnet-20250219-v1:0 us.anthropic.claude-3-sonnet-20240229-v1:0 us.anthropic.claude-haiku-4-5-20251001-v1:0 us.anthropic.claude-3-7-sonnet-20250219-v1:0 -us.anthropic.claude-3-5-sonnet-20241022-v2:0 +us.anthropic.claude-haiku-4-5-20251001-v1:0 us.anthropic.claude-3-haiku-20240307-v1:0 us.anthropic.claude-3-5-haiku-20241022-v1:0 -us.anthropic.claude-3-opus-20240229-v1:0 +us.anthropic.claude-3-7-sonnet-20250219-v1:0 eu.anthropic.claude-3-sonnet-20240229-v1:0 -eu.anthropic.claude-3-5-sonnet-20240620-v1:0 -eu.anthropic.claude-3-5-sonnet-20241022-v2:0 +eu.anthropic.claude-haiku-4-5-20251001-v1:0 +eu.anthropic.claude-haiku-4-5-20251001-v1:0 eu.anthropic.claude-3-haiku-20240307-v1:0 eu.anthropic.claude-3-5-haiku-20241022-v1:0 -eu.anthropic.claude-3-opus-20240229-v1:0 +eu.anthropic.claude-3-7-sonnet-20250219-v1:0 anthropic.claude-v1 bedrock/us-east-1/anthropic.claude-v1 bedrock/us-west-2/anthropic.claude-v1 diff --git a/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json b/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json index bd2f06b502e..b22336aecf7 100644 --- a/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json +++ b/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json @@ -31,14 +31,14 @@ "model_id": null, "cache_key": null, "api_base": null, - "response_cost": 0.00018, + "response_cost": 6e-05, "additional_headers": {}, "litellm_overhead_time_ms": null, "batch_models": null, - "litellm_model_name": "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + "litellm_model_name": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", "usage_object": null }, - "litellm_response_cost": 0.00018, + "litellm_response_cost": 6e-05, "cache_hit": false, "requester_metadata": {} }, @@ -54,7 +54,7 @@ "id": "time-14-13-16-469836_chatcmpl-3803a9e9-aa68-4493-94d9-247f354830d6", "endTime": "2025-05-26T14:13:16.795438-07:00", "completionStartTime": "2025-05-26T14:13:16.795438-07:00", - "model": "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", "modelParameters": { "aws_region": "us-east-1" }, @@ -62,7 +62,7 @@ "input": 10, "output": 10, "unit": "TOKENS", - "totalCost": 0.00018 + "totalCost": 6.599999999999999e-05 }, "usageDetails": { "input": 10, diff --git a/tests/logging_callback_tests/test_langfuse_e2e_test.py b/tests/logging_callback_tests/test_langfuse_e2e_test.py index 9087f2fbc74..9b845f2611f 100644 --- a/tests/logging_callback_tests/test_langfuse_e2e_test.py +++ b/tests/logging_callback_tests/test_langfuse_e2e_test.py @@ -448,12 +448,12 @@ class TestLangfuseLogging: completion_tokens=10, total_tokens=20, ), - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", created=1723081200, ).model_dump() await litellm.acompletion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello!"}], mock_response=mock_response, metadata={"trace_id": setup["trace_id"]}, diff --git a/tests/openai_endpoints_tests/test_bedrock_batches_api.py b/tests/openai_endpoints_tests/test_bedrock_batches_api.py index a6fae641ed7..4f27d0db892 100644 --- a/tests/openai_endpoints_tests/test_bedrock_batches_api.py +++ b/tests/openai_endpoints_tests/test_bedrock_batches_api.py @@ -7,7 +7,7 @@ client = OpenAI( ) -BEDROCK_BATCH_MODEL = "bedrock/batch-anthropic.claude-3-5-sonnet-20240620-v1:0" +BEDROCK_BATCH_MODEL = "bedrock/batch-us.anthropic.claude-haiku-4-5-20251001-v1:0" @pytest.mark.asyncio diff --git a/tests/pass_through_tests/test_vertex.test.js b/tests/pass_through_tests/test_vertex.test.js index cfb494da670..7b5edf6acd7 100644 --- a/tests/pass_through_tests/test_vertex.test.js +++ b/tests/pass_through_tests/test_vertex.test.js @@ -56,59 +56,74 @@ beforeAll(() => { loadVertexAiCredentials(); }); - +// Non-streaming Vertex generateContent can exceed 5s in CI / under load +const VERTEX_TEST_TIMEOUT_MS = 30000; describe('Vertex AI Tests', () => { - test('should successfully generate content from Vertex AI', async () => { - const vertexAI = new VertexAI({ - project: 'litellm-ci-cd', - location: 'us-central1', - apiEndpoint: "localhost:4000/vertex-ai" - }); + test( + 'should successfully generate content from Vertex AI', + async () => { + const vertexAI = new VertexAI({ + project: 'litellm-ci-cd', + location: 'us-central1', + apiEndpoint: "localhost:4000/vertex-ai" + }); - const customHeaders = new Headers({ - "x-litellm-api-key": "sk-1234" - }); + const customHeaders = new Headers({ + "x-litellm-api-key": "sk-1234" + }); - const requestOptions = { - customHeaders: customHeaders - }; + const requestOptions = { + customHeaders: customHeaders + }; - const generativeModel = vertexAI.getGenerativeModel( - { model: 'gemini-2.5-flash-lite' }, - requestOptions - ); + const generativeModel = vertexAI.getGenerativeModel( + { model: 'gemini-2.5-flash-lite' }, + requestOptions + ); - const request = { - contents: [{role: 'user', parts: [{text: 'How are you doing today tell me your name?'}]}], - }; + const request = { + contents: [{role: 'user', parts: [{text: 'How are you doing today tell me your name?'}]}], + }; - const streamingResult = await generativeModel.generateContentStream(request); - - // Add some assertions - expect(streamingResult).toBeDefined(); - - for await (const item of streamingResult.stream) { - console.log('stream chunk:', JSON.stringify(item)); - expect(item).toBeDefined(); - } + const streamingResult = await generativeModel.generateContentStream(request); - const aggregatedResponse = await streamingResult.response; - console.log('aggregated response:', JSON.stringify(aggregatedResponse)); - expect(aggregatedResponse).toBeDefined(); - }); + // Add some assertions + expect(streamingResult).toBeDefined(); + for await (const item of streamingResult.stream) { + console.log('stream chunk:', JSON.stringify(item)); + expect(item).toBeDefined(); + } - test('should successfully generate non-streaming content from Vertex AI', async () => { - const vertexAI = new VertexAI({project: 'litellm-ci-cd', location: 'us-central1', apiEndpoint: "localhost:4000/vertex-ai"}); - const customHeaders = new Headers({"x-litellm-api-key": "sk-1234"}); - const requestOptions = {customHeaders: customHeaders}; - const generativeModel = vertexAI.getGenerativeModel({model: 'gemini-2.5-flash-lite'}, requestOptions); - const request = {contents: [{role: 'user', parts: [{text: 'What is 2+2?'}]}]}; + const aggregatedResponse = await streamingResult.response; + console.log('aggregated response:', JSON.stringify(aggregatedResponse)); + expect(aggregatedResponse).toBeDefined(); + }, + VERTEX_TEST_TIMEOUT_MS + ); - const result = await generativeModel.generateContent(request); - expect(result).toBeDefined(); - expect(result.response).toBeDefined(); - console.log('non-streaming response:', JSON.stringify(result.response)); - }); + test( + 'should successfully generate non-streaming content from Vertex AI', + async () => { + const vertexAI = new VertexAI({ + project: 'litellm-ci-cd', + location: 'us-central1', + apiEndpoint: "localhost:4000/vertex-ai" + }); + const customHeaders = new Headers({"x-litellm-api-key": "sk-1234"}); + const requestOptions = {customHeaders: customHeaders}; + const generativeModel = vertexAI.getGenerativeModel( + {model: 'gemini-2.5-flash-lite'}, + requestOptions + ); + const request = {contents: [{role: 'user', parts: [{text: 'What is 2+2?'}]}]}; + + const result = await generativeModel.generateContent(request); + expect(result).toBeDefined(); + expect(result.response).toBeDefined(); + console.log('non-streaming response:', JSON.stringify(result.response)); + }, + VERTEX_TEST_TIMEOUT_MS + ); }); \ No newline at end of file diff --git a/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_converse_structured_output.py b/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_converse_structured_output.py index 9229677f32c..f0f1da7f5b7 100644 --- a/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_converse_structured_output.py +++ b/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_converse_structured_output.py @@ -26,4 +26,4 @@ class TestBedrockConverseStructuredOutput(BaseAnthropicMessagesStructuredOutputT """ def get_model(self) -> str: - return "bedrock/converse/us.anthropic.claude-3-5-sonnet-20241022-v2:0" \ No newline at end of file + return "bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0" \ No newline at end of file diff --git a/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_invoke_structured_output.py b/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_invoke_structured_output.py index d41072c46cf..9d9fff21cb6 100644 --- a/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_invoke_structured_output.py +++ b/tests/pass_through_unit_tests/messages_api_structured_output/test_bedrock_invoke_structured_output.py @@ -29,4 +29,4 @@ class TestBedrockInvokeStructuredOutput(BaseAnthropicMessagesStructuredOutputTes """ def get_model(self) -> str: - return "bedrock/invoke/us.anthropic.claude-3-5-sonnet-20241022-v2:0" \ No newline at end of file + return "bedrock/invoke/us.anthropic.claude-haiku-4-5-20251001-v1:0" \ No newline at end of file diff --git a/tests/pass_through_unit_tests/test_anthropic_messages_passthrough.py b/tests/pass_through_unit_tests/test_anthropic_messages_passthrough.py index 3d6ccae0e10..7498ef1b8e5 100644 --- a/tests/pass_through_unit_tests/test_anthropic_messages_passthrough.py +++ b/tests/pass_through_unit_tests/test_anthropic_messages_passthrough.py @@ -634,7 +634,7 @@ async def test_anthropic_messages_with_extra_headers(): # # Call the handler with headers in kwargs # try: # await handler.async_anthropic_messages_handler( -# model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", +# model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", # messages=[{"role": "user", "content": "Hello"}], # anthropic_messages_provider_config=mock_provider_config, # anthropic_messages_optional_request_params={"max_tokens": 100}, diff --git a/tests/pass_through_unit_tests/test_websearch_interception_e2e.py b/tests/pass_through_unit_tests/test_websearch_interception_e2e.py index bf50c1c9cd2..355e6a06520 100644 --- a/tests/pass_through_unit_tests/test_websearch_interception_e2e.py +++ b/tests/pass_through_unit_tests/test_websearch_interception_e2e.py @@ -64,13 +64,13 @@ async def test_websearch_interception_non_streaming(): try: # Make request with WebSearch tool (non-streaming) print("\n📞 Making litellm.messages.acreate() call...") - print(f" Model: bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0") + print(f" Model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0") print(f" Query: 'What is LiteLLM?'") print(f" Tools: WebSearch") print(f" Stream: False") response = await messages.acreate( - model="bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "What is LiteLLM? Give me a brief overview."}], tools=[ { @@ -193,13 +193,13 @@ async def test_websearch_interception_streaming(): try: # Make request with WebSearch tool AND stream=True print("\n📞 Making litellm.messages.acreate() call with stream=True...") - print(f" Model: bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0") + print(f" Model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0") print(f" Query: 'What is LiteLLM?'") print(f" Tools: WebSearch") print(f" Stream: True (will be converted to False)") response = await messages.acreate( - model="bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "What is LiteLLM? Give me a brief overview."}], tools=[ { @@ -347,13 +347,13 @@ async def test_websearch_interception_no_tool_call_streaming(): # Make request with WebSearch tool AND stream=True # Use a query that the LLM will answer directly without using the tool print("\n📞 Making litellm.messages.acreate() call with stream=True...") - print(f" Model: bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0") + print(f" Model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0") print(f" Query: 'What is 2+2?'") print(f" Tools: WebSearch") print(f" Stream: True") response = await messages.acreate( - model="bedrock/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "What is 2+2? Just give me the answer, no need to search."}], tools=[ { diff --git a/tests/test_litellm/integrations/websearch_interception/test_websearch_interception_handler.py b/tests/test_litellm/integrations/websearch_interception/test_websearch_interception_handler.py index b467822ac70..020c171a666 100644 --- a/tests/test_litellm/integrations/websearch_interception/test_websearch_interception_handler.py +++ b/tests/test_litellm/integrations/websearch_interception/test_websearch_interception_handler.py @@ -114,7 +114,7 @@ async def test_async_pre_call_deployment_hook_provider_from_top_level_kwargs(): # Simulate kwargs as they arrive from the router path: # custom_llm_provider is at the TOP LEVEL (not nested under litellm_params) kwargs = { - "model": "anthropic.claude-3-5-sonnet-20241022-v2:0", + "model": "anthropic.claude-haiku-4-5-20251001-v1:0", "messages": [{"role": "user", "content": "Search the web for LiteLLM"}], "tools": [ {"type": "web_search_20250305", "name": "web_search", "max_uses": 3}, @@ -222,7 +222,7 @@ async def test_async_pre_call_deployment_hook_nested_litellm_params_fallback(): logger = WebSearchInterceptionLogger(enabled_providers=["bedrock"]) kwargs = { - "model": "anthropic.claude-3-5-sonnet-20241022-v2:0", + "model": "anthropic.claude-haiku-4-5-20251001-v1:0", "messages": [{"role": "user", "content": "test"}], "tools": [{"type": "web_search_20250305", "name": "web_search"}], "litellm_params": { @@ -238,7 +238,7 @@ async def test_async_pre_call_deployment_hook_nested_litellm_params_fallback(): for t in result["tools"] ) # Full kwargs preserved - assert result["model"] == "anthropic.claude-3-5-sonnet-20241022-v2:0" + assert result["model"] == "anthropic.claude-haiku-4-5-20251001-v1:0" @pytest.mark.asyncio diff --git a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py index e5fb0ebdf6e..9d584446eb5 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -20,7 +20,7 @@ from litellm.types.utils import ModelResponse, TextCompletionResponse @pytest.fixture def logging_obj(): return LitellmLogging( - model="bedrock/claude-3-5-sonnet-20240620-v1:0", + model="bedrock/claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hey"}], stream=True, call_type="completion", diff --git a/tests/test_litellm/litellm_core_utils/test_streaming_handler.py b/tests/test_litellm/litellm_core_utils/test_streaming_handler.py index 20e064ef8f4..aad3de306c7 100644 --- a/tests/test_litellm/litellm_core_utils/test_streaming_handler.py +++ b/tests/test_litellm/litellm_core_utils/test_streaming_handler.py @@ -475,10 +475,10 @@ async def test_streaming_handler_with_usage( response = CustomStreamWrapper( completion_stream=completion_stream, - model="bedrock/claude-3-5-sonnet-20240620-v1:0", + model="bedrock/claude-haiku-4-5-20251001-v1:0", custom_llm_provider="bedrock", logging_obj=Logging( - model="bedrock/claude-3-5-sonnet-20240620-v1:0", + model="bedrock/claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hey"}], stream=True, call_type="completion", @@ -748,7 +748,7 @@ async def test_streaming_completion_start_time(logging_obj: Logging): response = CustomStreamWrapper( completion_stream=completion_stream, - model="bedrock/claude-3-5-sonnet-20240620-v1:0", + model="bedrock/claude-haiku-4-5-20251001-v1:0", logging_obj=logging_obj, ) @@ -883,7 +883,7 @@ def test_streaming_handler_with_created_time_propagation( response = CustomStreamWrapper( completion_stream=completion_stream, - model="bedrock/claude-3-5-sonnet-20240620-v1:0", + model="bedrock/claude-haiku-4-5-20251001-v1:0", logging_obj=logging_obj, ) diff --git a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py index 867a3e61bbd..7ff30b36309 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -225,7 +225,7 @@ def test_transform_tool_call_with_cache_control(): ] result = config.transform_request( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -309,10 +309,10 @@ def test_transform_request_helper_includes_anthropic_beta_and_tools(): config = AmazonConverseConfig() system_content_blocks = [] optional_params = { - "anthropic_beta": ["computer-use-2024-10-22"], + "anthropic_beta": ["computer-use-2025-01-24"], "tools": [ { - "type": "computer_20241022", + "type": "computer_20250124", "name": "computer", "display_height_px": 768, "display_width_px": 1024, @@ -322,7 +322,7 @@ def test_transform_request_helper_includes_anthropic_beta_and_tools(): "some_other_param": 123, } data = config._transform_request_helper( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=system_content_blocks, optional_params=optional_params, messages=None, @@ -330,11 +330,11 @@ def test_transform_request_helper_includes_anthropic_beta_and_tools(): assert "additionalModelRequestFields" in data fields = data["additionalModelRequestFields"] assert "anthropic_beta" in fields - assert fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Verify computer tool is included assert "tools" in fields assert len(fields["tools"]) == 1 - assert fields["tools"][0]["type"] == "computer_20241022" + assert fields["tools"][0]["type"] == "computer_20250124" def test_transform_response_with_computer_use_tool(): @@ -396,7 +396,7 @@ def test_transform_response_with_computer_use_tool(): optional_params = { "tools": [ { - "type": "computer_20241022", + "type": "computer_20250124", "function": { "name": "computer", "parameters": { @@ -410,7 +410,7 @@ def test_transform_response_with_computer_use_tool(): } # Call the transformation logic result = config._transform_response( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", response=MockResponse(), model_response=model_response, stream=False, @@ -497,7 +497,7 @@ def test_transform_response_with_bash_tool(): } # Call the transformation logic result = config._transform_response( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", response=MockResponse(), model_response=model_response, stream=False, @@ -610,7 +610,7 @@ def test_transform_response_with_structured_response_being_called(): } # Call the transformation logic result = config._transform_response( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", response=MockResponse(), model_response=model_response, stream=False, @@ -758,7 +758,7 @@ async def test_bedrock_bash_tool_acompletion(): try: response = await litellm.acompletion( - model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, tools=tools, # Using dummy API key - test should fail with auth error, proving request formatting works @@ -798,7 +798,7 @@ async def test_bedrock_computer_use_acompletion(): # Test with computer use tool tools = [ { - "type": "computer_20241022", + "type": "computer_20250124", "name": "computer", "display_height_px": 768, "display_width_px": 1024, @@ -823,7 +823,7 @@ async def test_bedrock_computer_use_acompletion(): try: response = await litellm.acompletion( - model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, tools=tools, # Using dummy API key - test should fail with auth error, proving request formatting works @@ -864,7 +864,7 @@ async def test_transformation_directly(): tools = [ { - "type": "computer_20241022", + "type": "computer_20250124", "name": "computer", "display_height_px": 768, "display_width_px": 1024, @@ -880,7 +880,7 @@ async def test_transformation_directly(): # Transform request request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -893,7 +893,7 @@ async def test_transformation_directly(): # Check that anthropic_beta is set correctly for computer use assert "anthropic_beta" in additional_fields - assert additional_fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert additional_fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Check that tools are present assert "tools" in additional_fields @@ -901,7 +901,7 @@ async def test_transformation_directly(): # Verify tool types tool_types = [tool.get("type") for tool in additional_fields["tools"]] - assert "computer_20241022" in tool_types + assert "computer_20250124" in tool_types assert "bash_20241022" in tool_types @@ -910,7 +910,7 @@ def test_transform_request_helper_includes_anthropic_beta_and_tools_bash(): config = AmazonConverseConfig() system_content_blocks = [] optional_params = { - "anthropic_beta": ["computer-use-2024-10-22"], + "anthropic_beta": ["computer-use-2025-01-24"], "tools": [ { "type": "bash_20241022", @@ -920,7 +920,7 @@ def test_transform_request_helper_includes_anthropic_beta_and_tools_bash(): "some_other_param": 123, } data = config._transform_request_helper( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=system_content_blocks, optional_params=optional_params, messages=None, @@ -928,7 +928,7 @@ def test_transform_request_helper_includes_anthropic_beta_and_tools_bash(): assert "additionalModelRequestFields" in data fields = data["additionalModelRequestFields"] assert "anthropic_beta" in fields - assert fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Verify bash tool is included assert "tools" in fields assert len(fields["tools"]) == 1 @@ -942,7 +942,7 @@ def test_transform_request_with_multiple_tools(): # Use the exact payload from the user's error tools = [ { - "type": "computer_20241022", + "type": "computer_20250124", "function": { "name": "computer", "parameters": { @@ -984,7 +984,7 @@ def test_transform_request_with_multiple_tools(): # Transform request request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -997,7 +997,7 @@ def test_transform_request_with_multiple_tools(): # Check that anthropic_beta is set correctly for computer use assert "anthropic_beta" in additional_fields - assert additional_fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert additional_fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Check that tools are present assert "tools" in additional_fields @@ -1005,7 +1005,7 @@ def test_transform_request_with_multiple_tools(): # Verify tool types tool_types = [tool.get("type") for tool in additional_fields["tools"]] - assert "computer_20241022" in tool_types + assert "computer_20250124" in tool_types assert "bash_20241022" in tool_types assert "text_editor_20241022" in tool_types @@ -1019,7 +1019,7 @@ def test_transform_request_with_computer_tool_only(): tools = [ { - "type": "computer_20241022", + "type": "computer_20250124", "name": "computer", "display_height_px": 768, "display_width_px": 1024, @@ -1044,7 +1044,7 @@ def test_transform_request_with_computer_tool_only(): # Transform request request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -1057,12 +1057,12 @@ def test_transform_request_with_computer_tool_only(): # Check that anthropic_beta is set correctly for computer use assert "anthropic_beta" in additional_fields - assert additional_fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert additional_fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Check that tools are present assert "tools" in additional_fields assert len(additional_fields["tools"]) == 1 - assert additional_fields["tools"][0]["type"] == "computer_20241022" + assert additional_fields["tools"][0]["type"] == "computer_20250124" def test_transform_request_with_bash_tool_only(): @@ -1080,7 +1080,7 @@ def test_transform_request_with_bash_tool_only(): # Transform request request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -1093,7 +1093,7 @@ def test_transform_request_with_bash_tool_only(): # Check that anthropic_beta is set correctly for computer use assert "anthropic_beta" in additional_fields - assert additional_fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert additional_fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Check that tools are present assert "tools" in additional_fields @@ -1116,7 +1116,7 @@ def test_transform_request_with_text_editor_tool(): # Transform request request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -1129,7 +1129,7 @@ def test_transform_request_with_text_editor_tool(): # Check that anthropic_beta is set correctly for computer use assert "anthropic_beta" in additional_fields - assert additional_fields["anthropic_beta"] == ["computer-use-2024-10-22"] + assert additional_fields["anthropic_beta"] == ["computer-use-2025-01-24"] # Check that tools are present assert "tools" in additional_fields @@ -1166,7 +1166,7 @@ def test_transform_request_with_function_tool(): # Transform request request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"tools": tools}, litellm_params={}, @@ -1262,17 +1262,17 @@ async def test_assistant_message_cache_control(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -1307,11 +1307,11 @@ async def test_assistant_message_list_content_cache_control(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -1349,11 +1349,11 @@ async def test_tool_message_cache_control(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -1400,11 +1400,11 @@ async def test_tool_message_string_content_cache_control(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -1447,11 +1447,11 @@ async def test_assistant_tool_calls_cache_control(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -1501,11 +1501,11 @@ async def test_multiple_tool_calls_with_mixed_cache_control(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -1546,11 +1546,11 @@ async def test_no_cache_control_no_cache_point(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) async_result = await BedrockConverseMessagesProcessor._bedrock_converse_messages_pt_async( - messages=messages, model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) assert result == async_result @@ -2108,7 +2108,7 @@ def test_request_metadata_transformation(): # Transform request with requestMetadata request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": request_metadata}, litellm_params={}, @@ -2134,7 +2134,7 @@ def test_request_metadata_validation(): # Should not raise exception config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": valid_metadata}, litellm_params={}, @@ -2146,7 +2146,7 @@ def test_request_metadata_validation(): try: config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": too_many_items}, litellm_params={}, @@ -2169,7 +2169,7 @@ def test_request_metadata_key_constraints(): try: config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": invalid_metadata}, litellm_params={}, @@ -2184,7 +2184,7 @@ def test_request_metadata_key_constraints(): try: config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": invalid_metadata}, litellm_params={}, @@ -2207,7 +2207,7 @@ def test_request_metadata_value_constraints(): try: config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": invalid_metadata}, litellm_params={}, @@ -2222,7 +2222,7 @@ def test_request_metadata_value_constraints(): # Should not raise exception config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": valid_metadata}, litellm_params={}, @@ -2245,7 +2245,7 @@ def test_request_metadata_character_pattern(): # Should not raise exception config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": valid_metadata}, litellm_params={}, @@ -2280,7 +2280,7 @@ def test_request_metadata_with_other_params(): # Transform request with multiple parameters including request_metadata request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": request_metadata, "tools": tools, "max_tokens": 100, "temperature": 0.7}, litellm_params={}, @@ -2305,7 +2305,7 @@ def test_request_metadata_empty(): # Empty dict should be allowed request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={"requestMetadata": {}}, litellm_params={}, @@ -2324,7 +2324,7 @@ def test_request_metadata_not_provided(): # No requestMetadata provided request_data = config.transform_request( - model="anthropic.claude-3-5-sonnet-20240620-v1:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=messages, optional_params={}, litellm_params={}, @@ -2358,7 +2358,7 @@ def test_empty_assistant_message_handling(): # This avoids issues with module reloading during parallel test execution with patch.object(factory_module.litellm, "modify_params", True): result = _bedrock_converse_messages_pt( - messages=messages, model="anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) # Should have 3 messages: user, assistant (with placeholder), user @@ -2380,7 +2380,7 @@ def test_empty_assistant_message_handling(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) # Assistant message should have placeholder text instead of whitespace @@ -2395,7 +2395,7 @@ def test_empty_assistant_message_handling(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) # Assistant message should have placeholder text instead of empty text @@ -2410,7 +2410,7 @@ def test_empty_assistant_message_handling(): ] result = _bedrock_converse_messages_pt( - messages=messages, model="anthropic.claude-3-5-sonnet-20240620-v1:0", llm_provider="bedrock_converse" + messages=messages, model="anthropic.claude-haiku-4-5-20251001-v1:0", llm_provider="bedrock_converse" ) # Assistant message should keep original content @@ -2446,7 +2446,7 @@ def test_is_nova_2_model(): assert config._is_nova_2_model("eu.amazon.nova-pro-v1:0") is False # Test with completely different models (should return False) - assert config._is_nova_2_model("anthropic.claude-3-5-sonnet-20240620-v1:0") is False + assert config._is_nova_2_model("anthropic.claude-haiku-4-5-20251001-v1:0") is False assert config._is_nova_2_model("meta.llama3-70b-instruct-v1:0") is False assert config._is_nova_2_model("mistral.mistral-7b-instruct-v0:2") is False @@ -2671,7 +2671,6 @@ def test_supports_native_structured_outputs(): assert config._supports_native_structured_outputs("deepseek.v3-v1:0") # Unsupported models -- should fall back to tool-call approach - assert not config._supports_native_structured_outputs("anthropic.claude-3-5-sonnet-20241022-v2:0") assert not config._supports_native_structured_outputs("anthropic.claude-sonnet-4-20250514-v1:0") assert not config._supports_native_structured_outputs("meta.llama3-3-70b-instruct-v1:0") assert not config._supports_native_structured_outputs("amazon.nova-pro-v1:0") @@ -2799,13 +2798,13 @@ def test_translate_response_format_fallback_tool_call(): optional_params: dict = {} result = config._translate_response_format_param( value=response_format, - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-3-haiku-20240307-v1:0", optional_params=optional_params, non_default_params={"response_format": response_format}, is_thinking_enabled=False, ) - # Should use tool-call approach, NOT outputConfig + # Should use tool-call approach, NOT outputConfig (model doesn't support native structured outputs) assert "outputConfig" not in result assert "tools" in result assert result["json_mode"] is True @@ -3191,7 +3190,7 @@ def test_parallel_tool_calls_newer_model_adds_disable_flag(): def test_parallel_tool_calls_older_model_drops_disable_flag(): """Older Claude models (pre-4.5) must NOT receive disable_parallel_tool_use — Bedrock rejects it.""" config = AmazonConverseConfig() - model = "anthropic.claude-3-5-sonnet-20241022-v2:0" + model = "anthropic.claude-3-haiku-20240307-v1:0" messages = [{"role": "user", "content": "What's the weather in SF and NYC?"}] optional_params = config.map_openai_params( @@ -3319,7 +3318,7 @@ def test_transform_response_with_both_json_tool_call_and_real_tool(): optional_params = {"json_mode": True} result = config._transform_response( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", response=MockResponse(), model_response=model_response, stream=False, @@ -3397,7 +3396,7 @@ def test_transform_response_does_not_mutate_optional_params(): optional_params = {"json_mode": True, "other_key": "value"} config._transform_response( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", response=MockResponse(), model_response=model_response, stream=False, diff --git a/tests/test_litellm/llms/bedrock/files/expected_bedrock_batch_completions.jsonl b/tests/test_litellm/llms/bedrock/files/expected_bedrock_batch_completions.jsonl index 8bb35ba95d7..c58963bb1de 100644 --- a/tests/test_litellm/llms/bedrock/files/expected_bedrock_batch_completions.jsonl +++ b/tests/test_litellm/llms/bedrock/files/expected_bedrock_batch_completions.jsonl @@ -1,2 +1,2 @@ -{"recordId": "request-1", "modelInput": {"messages": [{"role": "user", "content": [{"type": "text", "text": "Hello world!"}]}], "max_tokens": 10, "system": [{"type": "text", "text": "You are a helpful assistant."}], "anthropic_version": "bedrock-2023-05-31", "anthropic_beta": []}} -{"recordId": "request-2", "modelInput": {"messages": [{"role": "user", "content": [{"type": "text", "text": "Hello world!"}]}], "max_tokens": 10, "system": [{"type": "text", "text": "You are an unhelpful assistant."}], "anthropic_version": "bedrock-2023-05-31", "anthropic_beta": []}} +{"recordId": "request-1", "modelInput": {"messages": [{"role": "user", "content": [{"type": "text", "text": "Hello world!"}]}], "max_tokens": 10, "system": [{"type": "text", "text": "You are a helpful assistant."}], "anthropic_version": "bedrock-2023-05-31"}} +{"recordId": "request-2", "modelInput": {"messages": [{"role": "user", "content": [{"type": "text", "text": "Hello world!"}]}], "max_tokens": 10, "system": [{"type": "text", "text": "You are an unhelpful assistant."}], "anthropic_version": "bedrock-2023-05-31"}} diff --git a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py index 074a319a603..509db357c2a 100644 --- a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py +++ b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py @@ -53,7 +53,7 @@ class TestAnthropicBetaHeaderSupport: headers = {"anthropic-beta": "context-1m-2025-08-07,computer-use-2024-10-22"} result = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Test"}], optional_params={}, litellm_params={}, @@ -70,7 +70,7 @@ class TestAnthropicBetaHeaderSupport: headers = {"anthropic-beta": "context-1m-2025-08-07,interleaved-thinking-2025-05-14"} result = config._transform_request_helper( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=[{"role": "user", "content": "Test"}], @@ -89,7 +89,7 @@ class TestAnthropicBetaHeaderSupport: headers = {"anthropic-beta": "output-128k-2025-02-19"} result = config.transform_anthropic_messages_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Test"}], anthropic_messages_optional_request_params={"max_tokens": 100}, litellm_params={}, @@ -116,7 +116,7 @@ class TestAnthropicBetaHeaderSupport: ] result = config._transform_request_helper( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={"tools": tools}, messages=[{"role": "user", "content": "Test"}], @@ -125,10 +125,13 @@ class TestAnthropicBetaHeaderSupport: additional_fields = result["additionalModelRequestFields"] betas = additional_fields["anthropic_beta"] - - # Should contain both user-provided and auto-added beta headers + + # Should contain user header plus computer-use beta for this model (Haiku 4.5 uses 2025-01-24) assert "context-1m-2025-08-07" in betas - assert "computer-use-2024-10-22" in betas + assert ( + "computer-use-2024-10-22" in betas + or "computer-use-2025-01-24" in betas + ) assert len(betas) == 2 # No duplicates def test_no_anthropic_beta_headers(self): @@ -137,7 +140,7 @@ class TestAnthropicBetaHeaderSupport: headers = {} result = config._transform_request_helper( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=[{"role": "user", "content": "Test"}], @@ -163,7 +166,7 @@ class TestAnthropicBetaHeaderSupport: headers = {"anthropic-beta": ",".join(supported_features)} result = config.transform_request( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Test"}], optional_params={}, litellm_params={}, @@ -358,7 +361,7 @@ class TestAnthropicBetaHeaderSupport: headers = {"anthropic-beta": "context-1m-2025-08-07"} result = config._transform_request_helper( - model="anthropic.claude-3-5-sonnet-20241022-v2:0", + model="anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=[{"role": "user", "content": "Test"}], @@ -378,7 +381,7 @@ class TestAnthropicBetaHeaderSupport: # Model with 'us.' cross-region prefix result = config._transform_request_helper( - model="us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", system_content_blocks=[], optional_params={}, messages=[{"role": "user", "content": "Test"}], diff --git a/tests/test_litellm/llms/bedrock/test_bedrock_common_utils.py b/tests/test_litellm/llms/bedrock/test_bedrock_common_utils.py index b804f549ecb..5ce291aa165 100644 --- a/tests/test_litellm/llms/bedrock/test_bedrock_common_utils.py +++ b/tests/test_litellm/llms/bedrock/test_bedrock_common_utils.py @@ -32,9 +32,9 @@ def test_govcloud_cross_region_inference_prefix(): # Test us-gov prefix is stripped correctly for Claude models base_model = bedrock_model_info.get_base_model( - model="bedrock/us-gov.anthropic.claude-3-5-sonnet-20240620-v1:0" + model="bedrock/us-gov.anthropic.claude-haiku-4-5-20251001-v1:0" ) - assert base_model == "anthropic.claude-3-5-sonnet-20240620-v1:0" + assert base_model == "anthropic.claude-haiku-4-5-20251001-v1:0" # Test us-gov prefix is stripped correctly for different Claude versions base_model = bedrock_model_info.get_base_model( diff --git a/tests/test_litellm/llms/chat/test_converse_handler.py b/tests/test_litellm/llms/chat/test_converse_handler.py index f207c1d272a..1e75a2f1fcb 100644 --- a/tests/test_litellm/llms/chat/test_converse_handler.py +++ b/tests/test_litellm/llms/chat/test_converse_handler.py @@ -48,8 +48,8 @@ class TestBedrockRegionInModelPath: "us-east-1", ), ( - "us-west-2/anthropic.claude-3-5-sonnet-20241022-v2:0", - "anthropic.claude-3-5-sonnet-20241022-v2%3A0", + "us-west-2/anthropic.claude-haiku-4-5-20251001-v1:0", + "anthropic.claude-haiku-4-5-20251001-v1%3A0", "us-west-2", ), # No region in path — modelId unchanged, no region injected @@ -60,8 +60,8 @@ class TestBedrockRegionInModelPath: ), # Cross-region inference prefix (us., eu., ap.) — not a region path segment ( - "us.anthropic.claude-3-5-sonnet-20241022-v2:0", - "us.anthropic.claude-3-5-sonnet-20241022-v2%3A0", + "us.anthropic.claude-haiku-4-5-20251001-v1:0", + "us.anthropic.claude-haiku-4-5-20251001-v1%3A0", None, ), ], diff --git a/tests/test_litellm/passthrough/test_passthrough_main.py b/tests/test_litellm/passthrough/test_passthrough_main.py index c84d32d48f2..489357149c5 100644 --- a/tests/test_litellm/passthrough/test_passthrough_main.py +++ b/tests/test_litellm/passthrough/test_passthrough_main.py @@ -31,7 +31,7 @@ def test_llm_passthrough_route(): return_value=MagicMock(status_code=200, json={"message": "Hello, world!"}), ) as mock_post: response = llm_passthrough_route( - model="vllm/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="vllm/anthropic.claude-haiku-4-5-20251001-v1:0", endpoint="v1/chat/completions", method="POST", request_url="http://localhost:8000/v1/chat/completions", diff --git a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py index 366f659bdab..e11dbbd8915 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -3147,7 +3147,7 @@ async def test_new_team_org_scoped_models_bypasses_user_limit(): @pytest.mark.asyncio -async def test_new_team_standalone_validates_against_user_models(): +async def test_new_team_standalone_validates_against_user_models(monkeypatch): """ Test that /team/new WITHOUT organization_id still validates models against user's personal models. @@ -3158,11 +3158,17 @@ async def test_new_team_standalone_validates_against_user_models(): - Team is created WITHOUT organization_id and models=['gpt-4'] - Expected: Should fail with "Model not in allowed user models" """ + import litellm from fastapi import Request from litellm.proxy._types import NewTeamRequest, ProxyException, UserAPIKeyAuth from litellm.proxy.management_endpoints.team_endpoints import new_team + # Avoid injecting max_budget via global defaults; that path calls get_user_object and + # needs cache/DB mocks — this test only covers model validation. + monkeypatch.setattr(litellm, "default_team_settings", None) + monkeypatch.setattr(litellm, "default_team_params", None) + # Create non-admin user with restrictive personal models non_admin_user = UserAPIKeyAuth( user_role=LitellmUserRoles.INTERNAL_USER, diff --git a/tests/test_litellm/test_anthropic_beta_headers_filtering.py b/tests/test_litellm/test_anthropic_beta_headers_filtering.py index 447419b27d7..07c19db4568 100644 --- a/tests/test_litellm/test_anthropic_beta_headers_filtering.py +++ b/tests/test_litellm/test_anthropic_beta_headers_filtering.py @@ -265,7 +265,7 @@ class TestAnthropicBetaHeadersFiltering: try: await litellm.acompletion( - model="bedrock/converse/us.anthropic.claude-3-5-sonnet-20241022-v2:0", + model="bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hi"}], aws_access_key_id="test", aws_secret_access_key="test", diff --git a/tests/test_litellm/test_main.py b/tests/test_litellm/test_main.py index ce5873f5063..d19d1d1d756 100644 --- a/tests/test_litellm/test_main.py +++ b/tests/test_litellm/test_main.py @@ -150,8 +150,8 @@ def test_completion_missing_role(openai_api_response): "model", [ "gemini/gemini-1.5-flash", - "bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", - "bedrock/invoke/anthropic.claude-3-5-sonnet-20240620-v1:0", + "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", + "bedrock/invoke/anthropic.claude-haiku-4-5-20251001-v1:0", "anthropic/claude-3-5-sonnet", ], ) @@ -295,7 +295,7 @@ def test_bedrock_latency_optimized_inference(): with patch.object(client, "post") as mock_post: try: response = litellm.completion( - model="bedrock/anthropic.claude-3-5-sonnet-20240620-v1:0", + model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello, how are you?"}], performanceConfig={"latency": "optimized"}, client=client, diff --git a/tests/test_litellm/test_router.py b/tests/test_litellm/test_router.py index 73bd200f8d9..3df10901492 100644 --- a/tests/test_litellm/test_router.py +++ b/tests/test_litellm/test_router.py @@ -692,7 +692,7 @@ async def test_router_v1_messages_fallbacks(): { "model_name": "bedrock-claude", "litellm_params": { - "model": "anthropic.claude-3-5-sonnet-20240620-v1:0", + "model": "anthropic.claude-haiku-4-5-20251001-v1:0", "mock_response": "Hello, world I am a fallback!", }, }, diff --git a/tests/test_litellm/test_utils.py b/tests/test_litellm/test_utils.py index e984403a05b..bdb38ab65f3 100644 --- a/tests/test_litellm/test_utils.py +++ b/tests/test_litellm/test_utils.py @@ -1316,7 +1316,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/bedrock-claude-3-opus", - "bedrock/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/anthropic.claude-3-7-sonnet-20250219-v1:0", False, ), ( @@ -1614,13 +1614,13 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/bedrock-claude-3-opus", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "Bedrock Claude 3 Opus via Converse API", ), ( "litellm_proxy/bedrock-claude-3-5-sonnet", - "bedrock/converse/anthropic.claude-3-5-sonnet-20240620-v1:0", + "bedrock/converse/anthropic.claude-haiku-4-5-20251001-v1:0", False, "Bedrock Claude 3.5 Sonnet via Converse API", ), @@ -1701,7 +1701,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/staging-claude-opus", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "Staging Claude Opus", ), @@ -1713,7 +1713,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/high-performance-claude", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "High-performance Claude deployment", ), @@ -1851,7 +1851,7 @@ class TestProxyFunctionCalling: bedrock_models = [ "bedrock/converse/anthropic.claude-3-haiku-20240307-v1:0", "bedrock/converse/anthropic.claude-3-sonnet-20240229-v1:0", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", ] for model in bedrock_models: @@ -1883,13 +1883,13 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/bedrock-claude-3-opus", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "Bedrock Claude 3 Opus via Converse API", ), ( "litellm_proxy/bedrock-claude-3-5-sonnet", - "bedrock/converse/anthropic.claude-3-5-sonnet-20240620-v1:0", + "bedrock/converse/anthropic.claude-haiku-4-5-20251001-v1:0", False, "Bedrock Claude 3.5 Sonnet via Converse API", ), @@ -1970,7 +1970,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/staging-claude-opus", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "Staging Claude Opus", ), @@ -1982,7 +1982,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/high-performance-claude", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "High-performance Claude deployment", ), @@ -2120,7 +2120,7 @@ class TestProxyFunctionCalling: bedrock_models = [ "bedrock/converse/anthropic.claude-3-haiku-20240307-v1:0", "bedrock/converse/anthropic.claude-3-sonnet-20240229-v1:0", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", ] for model in bedrock_models: @@ -2152,13 +2152,13 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/bedrock-claude-3-opus", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "Bedrock Claude 3 Opus via Converse API", ), ( "litellm_proxy/bedrock-claude-3-5-sonnet", - "bedrock/converse/anthropic.claude-3-5-sonnet-20240620-v1:0", + "bedrock/converse/anthropic.claude-haiku-4-5-20251001-v1:0", False, "Bedrock Claude 3.5 Sonnet via Converse API", ), @@ -2239,7 +2239,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/staging-claude-opus", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "Staging Claude Opus", ), @@ -2251,7 +2251,7 @@ class TestProxyFunctionCalling: ), ( "litellm_proxy/high-performance-claude", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", False, "High-performance Claude deployment", ), @@ -2389,7 +2389,7 @@ class TestProxyFunctionCalling: bedrock_models = [ "bedrock/converse/anthropic.claude-3-haiku-20240307-v1:0", "bedrock/converse/anthropic.claude-3-sonnet-20240229-v1:0", - "bedrock/converse/anthropic.claude-3-opus-20240229-v1:0", + "bedrock/converse/anthropic.claude-3-7-sonnet-20250219-v1:0", ] for model in bedrock_models: diff --git a/tests/test_users.py b/tests/test_users.py index 30e34a95f4f..05253a19aa5 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -335,7 +335,7 @@ async def setup_test_users(session: aiohttp.ClientSession) -> Tuple[Dict, Dict]: i=0, budget=100, budget_duration="30d", - models=["anthropic.claude-3-5-sonnet-20240620-v1:0"], + models=["anthropic.claude-haiku-4-5-20251001-v1:0"], ) user2 = await new_user( @@ -343,7 +343,7 @@ async def setup_test_users(session: aiohttp.ClientSession) -> Tuple[Dict, Dict]: i=1, budget=100, budget_duration="30d", - models=["anthropic.claude-3-5-sonnet-20240620-v1:0"], + models=["anthropic.claude-haiku-4-5-20251001-v1:0"], ) print("\nCreated two test users:") @@ -360,7 +360,7 @@ async def setup_test_users(session: aiohttp.ClientSession) -> Tuple[Dict, Dict]: "user_id": user1["user_id"], "duration": "7d", "key_alias": f"test_key_{uuid.uuid4()}", - "models": ["anthropic.claude-3-5-sonnet-20240620-v1:0"], + "models": ["anthropic.claude-haiku-4-5-20251001-v1:0"], } print("\nGenerating additional key for user1...") From cae86136608d6a160cdbc46e42aa3d190a13b427 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Thu, 2 Apr 2026 14:10:49 -0700 Subject: [PATCH 19/32] Announce April Townhall (#25021) * fix: replace hardcoded url * docs: announce april townhall --- .../blog/april_townhall_announcement/index.md | 35 ++++++++++++++++++ .../docs/providers/azure/azure_responses.md | 4 +- docs/my-website/docs/proxy/team_model_add.md | 2 +- docs/my-website/docs/realtime.md | 2 +- docs/my-website/img/april_townhall_banner.png | Bin 0 -> 50618 bytes tests/llm_translation/test_azure_openai.py | 10 ++--- 6 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 docs/my-website/blog/april_townhall_announcement/index.md create mode 100644 docs/my-website/img/april_townhall_banner.png diff --git a/docs/my-website/blog/april_townhall_announcement/index.md b/docs/my-website/blog/april_townhall_announcement/index.md new file mode 100644 index 00000000000..b81f61bae62 --- /dev/null +++ b/docs/my-website/blog/april_townhall_announcement/index.md @@ -0,0 +1,35 @@ +--- +slug: april-townhall-announcement +title: "April Townhall: Friday, 10 April at 7:30 AM" +date: 2026-04-02T07:30:00 +authors: + - krrish +description: "Join the LiteLLM April townhall on Friday, 10 April at 7:30 AM." +tags: [announcement, townhall] +hide_table_of_contents: true +--- + +import Image from '@theme/IdealImage'; + +We are hosting our April townhall on **Friday, 10 April at 7:30 AM PST**. + + + +{/* truncate */} + +## Agenda + +- Product updates and roadmap progress +- Reliability and security updates +- Open Q&A with the team + +## Register + +Register here: [LiteLLM April Townhall Form](https://forms.gle/hvyVXwbFjzJQE7dEA) + +We will hold the townhall from **7:30 AM to 8:30 AM PST on Zoom**. + +For security, attendance is restricted to corporate emails. If you register with a non-corporate email, we will share the townhall slides and accompanying blog post after the event. diff --git a/docs/my-website/docs/providers/azure/azure_responses.md b/docs/my-website/docs/providers/azure/azure_responses.md index 34ec0e194f7..de085001ba1 100644 --- a/docs/my-website/docs/providers/azure/azure_responses.md +++ b/docs/my-website/docs/providers/azure/azure_responses.md @@ -246,7 +246,7 @@ You can also call the Azure Responses API via the `/chat/completions` endpoint. from litellm import completion import os -os.environ["AZURE_API_BASE"] = "https://my-endpoint-sweden-berri992.openai.azure.com/" +os.environ["AZURE_API_BASE"] = "https://my-azure-endpoint.openai.azure.com/" os.environ["AZURE_API_VERSION"] = "2023-03-15-preview" os.environ["AZURE_API_KEY"] = "my-api-key" @@ -268,7 +268,7 @@ model_list: litellm_params: model: azure/responses/my-custom-o1-pro api_key: os.environ/AZURE_API_KEY - api_base: https://my-endpoint-sweden-berri992.openai.azure.com/ + api_base: https://my-azure-endpoint.openai.azure.com/ api_version: 2023-03-15-preview ``` diff --git a/docs/my-website/docs/proxy/team_model_add.md b/docs/my-website/docs/proxy/team_model_add.md index bb4238055b5..4aa286f3e5f 100644 --- a/docs/my-website/docs/proxy/team_model_add.md +++ b/docs/my-website/docs/proxy/team_model_add.md @@ -26,7 +26,7 @@ curl -L -X POST 'http://0.0.0.0:4000/model/new' \ "model": "openai/gpt-4o", "custom_llm_provider": "openai", "api_key": "******ccb07", - "api_base": "https://my-endpoint-sweden-berri992.openai.azure.com", + "api_base": "https://my-azure-endpoint.openai.azure.com", "api_version": "2023-12-01-preview" }, "model_info": { diff --git a/docs/my-website/docs/realtime.md b/docs/my-website/docs/realtime.md index 15a838bb7d7..08f1e47fa73 100644 --- a/docs/my-website/docs/realtime.md +++ b/docs/my-website/docs/realtime.md @@ -82,7 +82,7 @@ Run this script using node - `node test.js` const WebSocket = require("ws"); const url = "ws://0.0.0.0:4000/v1/realtime?model=openai-gpt-4o-realtime-audio"; -// const url = "wss://my-endpoint-sweden-berri992.openai.azure.com/openai/realtime?api-version=2024-10-01-preview&deployment=gpt-4o-realtime-preview"; +// const url = "wss://my-azure-endpoint.openai.azure.com/openai/realtime?api-version=2024-10-01-preview&deployment=gpt-4o-realtime-preview"; const ws = new WebSocket(url, { headers: { "api-key": `sk-1234`, diff --git a/docs/my-website/img/april_townhall_banner.png b/docs/my-website/img/april_townhall_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..e589101f2fcf17133c49c368355ff96bcf463b74 GIT binary patch literal 50618 zcmb4qWmH^Cw{2s=-QC^Y-5r|73GVK}-Dwj0tc4>!Gjar6Wrx-?)T%~_v5}X z-r7=g*P2x|Yme^UyH<6*FTei=U?|Bc$^oFD005|u4e-7LwX7&DZK45Gms3=c{f}b| z@L{kV0DzOTr#nzyib7A{fCB#ae@gu8Gqdn;{Wtwz?4#bhrGIM&0Onc$7ta4H8`09r z!{UQ*@o~_&e>DCf7Uu)w*!%}G{EN;1gGK(uUp!qsKR6oyVs{Ww`U6{jU zu#faV1_k{g@e@1%5drDLZ-oJXf`)~LMTA5C(2D|t_;CpXfQ7^SLPUBMsCFE1D&s;gyj!cc%qur#1C&TX=*Qw_eck>w0-dq-Qj@v|S3w z%`xg&dVYy49hm=Uh8XHY*8e5r-**1h@!{mh1VDd?fP?%zL&+|Z*fQN zFJZ`E7XeaYD#UdNf;`QAY6x_T7GC{dZGDqpt4#&5P`6*oU|9{@_c5lXnT`*K;&I_B zC=R~F+v~voau2dVEo(*u%Fg%5`kp8|WrUS(UJ5X=iC_r)Q`<4*@wc+OL1KicIf+h7 z^NdR+obWRhf|XTU5aJA!(LbTKNigsx7Uoh<@LeX(^ciEhR`oV9qTuB@|3y$0`vOQ+LyrGt* zw~}gT8Ln&bWSmJm8h_o6$I7bB^LfKGgTigitGXmzHBd~9XP=cMfq)L#9l3BzxeXIe^nnCy~TsMtuwMc}*xcHUD&^hBP{;m`mBb zXT$7kivr+I%0nO$o+2V;1&{Y=+7eoctL-i(@r!(#;7RGj@F-zaW~Hh^0nv3}XO9p$|XPk=Ga*BHM5KFsd}95lCZWhZ$F0WWtvMsLt^UVlgIfK$xO2 z>bM_39`rz@u#dkRscxg6lUYd+Dg9&+Le>PeF9p{o?^HB!gv}^e>N6l0&lxPoF3P{2 z+lsM>Cqv3BTN=bc70Kyvl0@*AY7!k}*iL@2Y;8(3Sh#Pyuan0iCKK>fGJ;SoJose` z8Z;;pa@EqYYI;=Lo0dBEHzI-ZPw1wpNY?LFd9bh+b{Y-s={$lbsh3GR%_oZNC8l3G zfo=$kg4UyYK11nkgriU*ri~juBT8^1Dn6XpN3v~;b@K@97%KIS&$Z2f-Em;1V z+}M9@{tK_qNXHMk8+TbV_JCVx=_Hh(*$uJTh{6-WdlNoOx3m>)QEL332{i{_(FyQI z0N?J*kY5w{5`J5uhoV+rM5|^LgUZ!Z#(urGz+QOL+RGzL;&03jN6};4Rvvd1p@=_4 z+%R^v_K(v1+@bsI)QIG&A*e-Y2tI}Sk2E5OZC#fp{uG2I#yr`xtCmyPtu6DqF2wUdKdbV7+=n*rBEs#m! z6k}~O1Y|3)_)lE;c zqQ(2=XMF>~Ulx@li1s)0gUtk+^~niV>Uwg{5_t&{%aYPtIrq_Riw&GA)pRJMT*dKW ziJY5R!a8Hl@)7{Ye87oA=>XGgzvo65ZK2nQNvxTF!!l2~^?02s`e$R#krpo1+YhbP zvxcW4OJ4p8Vazff@}}yoRDGEJf5Mf@M|}5v>!|g?vXjzEK8k;)ONJhH5wRqM^jKnR)kgKhXy9zB)PVj(AX^g!=`E3Z} zAM9=`CR~+%y)Yk`i@0g5tDC<|3?t=rM0{JPsTJiXc#-=Tw4!ApyI1k#qsW&mR7NH4 zt#nV>5<}PpD*YqW5cPTs3pwPX(v4xItwJ`uYh9Ewk!|+1Is);y?Y_03Vb`nm5v|z6 zw5CB@{ygqJRh=Wu=A2L15{I<8UIZK^rvI>&cI;w4l#{<^o)KYPai+x4E8c*`(udQ| zQ>N*=d9CJMfs%^|lE*zn2Fi#d>ubh-dYcK48XeOR?F2X{UpoM2;P~S$>n>hQA;P4lN4wjzOtJ zk}Y4KEX5fWCT7uX0V}xmh8QPK|3uMs#9#z*j{UOAw=9GkhptSvmn+~t9;cCq-_fYJ z)-E_p^TK3yppm26O``3 zJMQgjXNz!RQ0iut&sy>2W*`Wvk0`+6^A|asTS(PEft8X|nB$^H6J_Mi{7EAmfxpg_ z2Nu^Saz{L5{U&q*n^@@+wBaqUTmgQWU3JpIy~=1!y7~7oDx< zJMWzQR;yd(9#6%BJY!b2W@$wmy=ImIk)p&u7yw+EgMe{6Ze* zOvgrfX$lf`Jss$!Z;~pU$I$)kIfRPNwY^3P5=`%chAtMraHS-k6z)C!)=pyD+k4v8 zyKgLN6}+Z4K;iM1mY6ncrg(8cUS(hI#j8J1JUq8_4E%B&#!RM*!$L=r5IzYOnR6MX z$sbdmibK*-aN{Fxv(S67KzovXM%=DuI}qdC4={4CC`1!$V76Q<>E$icu%(nc!FwZc zz9T9u-_zGU!rVZQ(JYX$JW~9^HJIcuWSG&l3wOQQ)sfz*?r57vV4oa5sra){+J#~s zsG3WYw2?Tr!`K_sKcL(tL$K2wtgjcM!&A>Zm+QVE$376R46p5o6&!^U=fs+JC2IMn zGr`NOu~~HT#e!)^PRki{4NixvuJWa9i(ppeJ0mizVkxm>D`APM>^p$d@h+xL=J}I+ zS0c3BgFbAfr5RV&-d=rW#pJ*l*G$d%1R4|`e(2(_lf*@QOn%a3S(;O)aLNqQ`_K-7 zLnK-y)gnF)tcj5$_cf)?u+ofNt6j8gMZQU&5#LpEppt?9luRYFZaY$yHkKlPv?@(i zx;3PGn`^VW*+B8A$93ANMH{mQjDu=QWe~~I?*R_LbV?yB6>0`(i0VeiV!N+aFB0WJ zbLKi3?8|!4ZMkcgj{#1N3Chj#ISr|R;5*_ROQM<<)ULjGL4-CX;EnljMeho}d`P0( z!GwK*-uOE}#rTgO-zJCwIKizCLLSOrOGbu&?&BlXx20ndN3xnq}hq zDY&2=up8$SQ=fi#W?#jBVtgR-a)PHC0#l9c?AG(w-NG~d>#PJ#2WM^R`7c2N{e`2t zVK~}@Rcb15P?}Gc#jX~lN;UY=^k_n?^c~QZE+_>3m{5wg>^iK+BRB@| z42RfO59F{SH4UNP!yt4;-RR8qsjKAgqV86SsinUIevi#(rrvXpo{YKaqhllH#I~gZ zg+k-chUsMyb&q4)?q~+=(`Kc(R9>#SuM?=_%YQL(zXRgwRqs>p8IEfho2DreL(Fh> zakQs|`s~@KDr6ay+RAM*7a^ot2DDDX^yz+o@rQ=RZ|L6v*P82T#FWrL&oz=q*0hUJb8%p8O$TR?WYFhO0~Av5#*a3VtO;nnoLF0$>KhTq?Zk< z?|^INmEbgb_ye%J1@Qusd#*=`Bd0)jahe;?{RR@f{!BJlU=(A4cO{6w~-GcP5cR-?#VK}n6B90mFcKV zMzXXZgafKIC3;zBkqUi#yytH!B*B`w^?d?Gxj#fN!m6*C_;>Ml@gE@;iUtxk$V!Dl z7j#tg4yvl_#VITU!Csud2uBAtN1OtcimN^74{>+lv=y(ft4S|e+I>~eBIqlT4TzZ1 zrCQobe5MOLt>+1tieGyNAmhzu|KBoK({pCCsS?YSGV^n$9#I1ayfUlz*hon6$2U4f zTj)7uaE2h`SB$;c^i8YqEkeOT^HfXyS{2e7IwYnflv}W+BGmd zD~IVX%rSvb4LW8w;D)Fd=-SS~yp-6FC`t2)bV)U>wFCJ=8`~DT(RecTsUKBl(frPL{!rLozClrIr@N z)2|(4lhJnTGibqZ)WId7*d3_g=lQD)>CEKEe8pk9|L^KL)w~9_jmAtmFW3aVZH9xJ z*O{yN73@h|9qU9R_ZKr>?edroq8jghaOx99b-LaLPKIdMnXESa-<-u=xcz$Y?PAa} zXoBf6W}8l8g=iDG@pH)f^RI_tpTQOT^ndhPYDh1_-DwS}l;l#|YApk(5jzcwly;bF zCL>Zt*{N^9^!vvPXIUProJ_BX5+q3x{5Z0hM}f0p8O$EizER^ti?HBwBXZk;Df6dX zWAIw|Ie~@-WWAtUcucw1P7EV=u(t|Tu*m!JyS8BLufWQHrBr6tQZ$`rp-DO4-nTu5 z#4)N$4@Pmkk_|#3J$1eTfbRPJnF-@tSS~d}@K3Y?+K} zr|ywtmFN$sxk%I8>lb6Nr92uJwA5Ac8*Pv;`@{S$S;)%Ju_!si1vxCDmygPO5F&Ixjd#D zT<5ViwP@SIpPbs}g1hZj^LJpH>YMFXv!AyA5J?a1t-era$OoV31Wno&DVuw!$WH9d zKHiI#Ao^NczXM46u#p56vigPu&j#c&xx~zVTJvdEG(t)dYbI;BPJXT?Ue&w<^!n_P z7`g57vHoDb(7|d}ppDz0uW{1#x_;ykBA-fgfubyp<13BVkB8Sz$PA z`J~{;Jf^ZhD%PD8z_4)Lag(tNuSQZ;a`=^bsi%FGDphltAjEO3gq`2uK|A>JnQsCs3mG`eUu5WWy>Q|Qt)4j; z2eql2^?xD^Z&!*{wlSuSjrjvW45nS1}H!A^>kmN?`0`FbSD-7oj8W=1(w)e9J4f zOAW29No+wEc?SN4Km-?i{EsBnLSxL?5w z{_vJeDA7nm(jLjLF-!SBD!{Lp>EnTWQ?N z3M-{V)sI^PglxvVV+GO1YQ_e^HaqwV14b=}V$$VLRxK&wo`memd~D?d-P`n4>fz43 zWD9h5=p^YU==Q}opT9*}iy)`cFz~<|A<29n7YZTG#3b5h-OGhf7F+OWRu>4#5Q$hb z>s@w0rJvjDT29qSSJJMlE+b8z8lKqTQ}X?$5H*snB}IJhX7PPNM&!`6lUB$ z87;9CG-+mzaNSHw zg-}5&r6?WZJvbk+Kc7b{Z0v-{fKEzry{ zCC-(&jE?dhqBLuE2P`SS5ClPK$V|%2eU3(DH&$A1?Q`XZ@b?Kt@Hb{!%BwxfVhg6H zGcHwrTFdpbhqM_SI=jpaM?K2Zi~DJ8bvg^-Covsbp86t_%~+)z8O%YgD0i_o1sZT8 z*e;uicIJ&8hcxz;+8s33QH6ssLSsTR1x%R~d-X>%Ml&}%*q3u}3(!2`B0E7`Cadu~ zjpG4h2Dsh~(9R$lm^$d2o9fySoWAV@1Y3ikU))$@Crq(O)(J0=Z}}?EdDiscK`$WD z;KCp9Q-Z3q`-{2Gn(nIia8_|7GXqQ}aKz9BPrsI&>jXh*Klem2rl}+|Pp3K0l6+G~ zv!BHaDRCtMmvFR6J2y8)Qv||5Ax&?Ru8D`lbjn$jfX6rmtXS@NLkIvOh0^A;AO=U%PhUV z?dlrj+%$9XuZQA#-#1c>)Xyq@BdRDRXv|R+*2AHs@iZo-j8p1LRHoZt+Nx z{i8i=Y=#I>j{JC8WgZ5ew*qPAgK~!>PgpS*DkE6&j-rkSLEJgT$R-IY+?@EH-5^l{c6O6`5i=Zrvzo-!dLcX9zt~i2x)V|gM{xyZa_*OLI;FD z`U|}9B=HnPOgG58!O?D5VVRicxZdgE8kzQWSo2t5{DzaPq@SK{p(&q=VPZQI@;UvgVbHtvd- z=n{vHn+rKDb`OZetx?>-%gaBc&xSjM9AbT{@sEgDDk|{R zkY9*>-_G2ITl`mTU$Z)E&=l?W2F2E~r+j%2^z1h%T{|Zbcq~C^EIHIWIi#@>86SZ{ z4=E9Cr4G~t2}hRq~9dy?Z<<0B(y(oYd_ z1`dCcG(|7OT)V}b#4tUD#LH-njvurkP}0-|8dUhC(L{se>FMS+sbY-q-DsTBy9c?V zv)*b+M>GZda0a*pFz99cpr;c4q`|S6ZPb>*N*lb7K^zDK{m zi0n{iGw4@gMJz$YHfKW@R}5qxB5IE9L6ct~)34ITlb?TuGMHZ5#A0OkFX+4j^noQ- ziG#hd&s;v7e@qAGsvnDAyL#d^Pna1yk2QM2L@EvBH9v7$atT zy}D;wMXVG2`57oNKzY;9>(#P=uLTG_<>67lctY7QzP!LjP5D7ZaT?t=A~%9B$9VDU zrC>KL#E02!sKf7?(!25z#sNuDS}9+}WQPlJfD8kR~TRuIG`U+<84ew zRnG>7E2eLQt6{7gBEIBj5bve?b9!9cN5Bn4w?S_Zg{=I{Ll>oA=E>g|6*wt|v>Dz} zYzBj(hT6_#hjF?;HGPw~%hJ$lJQ6vOB)*Q$`PyH8&sa5ws!dJttBK@0<>J`t@|ld$ zJbUCo%-+!bKq!F`vb&^n3#t+s_4q9V@*JFr`<&1%C1)wp*kk`0!gsMhgf2O;ur>7; zA^vDa?*RIE?~(D*A+>^qa#V^X`RUL*iogqId5eDnv$~321RPO$n}u8;EL9LD2{IMH zO(X%g{E$H~FqtRTQ2pmSpoa8swBgzW>NC|znVA*c4kSQ@M&y^y3LMOW*+EiFhIp06 z{a`&KAA71W<)Dycec|5aMLb_UAsM(j)l6raZ0r*0B4XX(NJqWuvyj{n5*{{Ehep(> zfgV?yhUi2zDUPGF^Sa8`-zdvE#SQWP!RM_dwmVuo|LY3e#qRvv#0JN(Q1#rc(^o zAM^c8e##uv0Yj2m-Z|QMo(fGAVi!R2$sAh`*@?3e}+Y3 zO*A#f9{$gqalGAMc>72|?{;)gC|R1y0Ho-Za263+n=T!Kx6b%gv;KhgEcSxMZ(He| z{*#6zva~Qe=|wNXlsx5$aw<&kfI;lkf|#>=W~Mn*FGFj5n7;|1+al&h!3I7jNVryt z4EK_t19H0K6piz6waic*|BTR5q5JC!O5WXxourBNOHTXUBg9upn??!5YVtZ|rn3)P zOzl0>_^5WF{GpmjZIi-P%&mdVIs zTcokmc2FdNCFf_;q>P@R*#u0j8+fnL)MD|3lG9YiXx5os1jBt|b@$9eRnvI)iq{gj z>(qvT@`5|Cal{nKc^RYxyw6}AXCJ*1r}?#XMK3*6`5ZOgzT#5_i5fWy)iY;sxchc~SSt0-Zg{5N@Rs*aW4$sq)dusmy(iDrwoQH0K;r)W*=Wmh zxPwi;bu>*G51iIwrHS;CUvLii%F5NpUy($aI4j@`l%|^TsB+E{oU*I6##?09$WqO| zUA69q;R@~YuUI*OH|l5@n}LK%@*sN7Qi>Co;m^`mlkN>s=Ggne9yW2Mvt`N(nuZ!m z6$OUT_h6MD3QGL`BKzHw7SxJb3_zTD)G}$`X;M^1^)6R0AUX)^!J74{cSo;U^C+Qd z)rl6Uz&_Qu2-5$=!$o83&RQ7RX%0+7v(|9s5SMSa5@4 zN+2Zl>!Q=1T=Ij++&*1j=cX8YwcO;)U~TCO)sotPj;VBOS@n33gzQh+Ax2a6 zoJ9LJrZ!5TPM#)0pi1c<6&Lm2875PF)|VIO*nxR+AFp%O_P#6(eq}$h8h#$bz-s}e zOuU`?yM(D>vU0O>HMM@$4Fsh`cnOUsDJAtYN<$7-21Psz6iOX<>sTkm!q&kJ7^$oy z4#bI_#Xogs#hxI3PWz`pmvN8KcdbxrZfA1?^QCpzaoT14lV7#wh<$!39C5BYhTcLh zW0EQQsf0k7U(G+WYej8%Y{86b@wRtTk%K(tNxvfYpyjM{V_Tc&I@|x+h1<1TgM5r_ zv4;L6QVm+l{p*VLhR8V!po91g=ln*shgYc-L|x;;qJ9iBDZ5UqW?CtX?;|LkVX2eJ zNRtMo!7b@+nlF-9wxoSA&2`(88nZVFecUMi=H;2i*F0KlI`&sj1*7tTsOT85?u+`01RX7rV z)B*Tl;~!b-2wQbg9W&q4fm&JF`p+6Qa>=DHRdzp*<$_4{H%+A{h$of%J5J5&Zg?t6 z?W`IN^19v_On-m1(!mBKE|(PDv!_myR4w|APzmspwR9P5N$pgWMU9634et>9;r$>X zvEfsO#%-#3nYiR%IxIpJXsOoZxvwHrtn|;{&|TWlK9aQ6%F@#w{w$0RAr%s;E4(Hz z;J$9#UgCFK?XOmuPXmBAhGIrF)WZ?@L@#QmZ@+!yoq>!xPeh2R=Ibl1hQ$}DWvP%^ zuE_i_^Ef(Vn0Yad5)W*q8?VJ>6nRA26J~u!69cOIHQ)EX-XvFC9X?rr=F z0#!Ck!CtUK;CkGlmWtnY9u9p{DC+REr)15`*)qkU4G2I{`etWfE_8D|+AVkhd|vpD+d-Q)OVg@h;LmJu zME_)6U$=mkP8)0{R_@;ku}YiJ4Jf5%Hz|^{r57s2dbrkT?5VoTkXKU2-Xmc3Zr_W( z5|+)_A5C)GwFIfuFY!{$DQKU4Wr>IiB- zcUPQ=fFBYRbd}9v`9N?J)PH1LDF$Nnl@1}ms5M%RzgIl{?qh(?lbBT(A{JmECA%5J z_n+aP50Yd_XO=~j>MGGqlO(Ks7)`$}u%wGFs1}>`q7slvLMfLw*ME0-2bd*B>NiMR z?!PKrS8=mpR}<1V=)k&{Ii>@ju`K4IJW)%It&@wC%#?-W)OWGwx@rHpQasQog^1E3 zy;ywqW#4Z$NJE1gg69wVu-$hW(N_je{C7ysFgJj`0*aHc&DQ z^6Yd$Ia*E~l1bg1pQ2kMfs%$?3*+8PtWKbK?_naFFgA|dT;yCoxl^GbN;_y#gr%hF zAJ56V!Re1Yy5;F=watj4h~aS=8c$qI{71Hl%f}$j`B2B2Z(1J{y-fI@A>Mdyqv; zZxihse^&T{qy>%8mO6$PQ!83*kcZ{wfiS>Rfuq{5Wx?J{;)Yu9_8i+!KOsM0Xg3dcIi{^`5xtv@h~Y3TWXbt20%!EdfJcXBYwv(y1ryHJE&N3|3T2X-RIKo;WRg^7R1>kUud(dskRXia#y4s>`XBCwe5fV^ zJPTDjefM|BT30stiv0$X8&Y}VM<_U^DnZbhdxSIakJx0fZPA=aI(QDvQqQsK+wjJC z4RuVt6v>P_+b#q224!#B_wN9x7jZh@Yyq$`+s7EpJC9@SS9@_b#nu3Q*#)0?jvX3* z^dU|dmx$!F*lpe{&g9EGfWf^&g>Ca`Lj6JJ$#vK*Ii24)15p97k!rAoVR0cNqnM{? zQ$D|Pwl`%-u+#g?QyO$0p&g}kZgfR(73a~HT(8Rl2(Y9{`XZEPVzVxh>g%75Z9@CS zOB1)%uV>ebLJV_;A3tH?*LmmCUvGpVIGqr(I z88Ni)fUR!I#k$~(z`+M&mFrsr;<;GWVI-HXPDLTYxzzEtPaZ72Y@!HUUWUs%a`Ml2 zQkA6(&`41)4IVY&E4W zL0QS#JD`<$uj_WNR&B1kZ(Vw^W~X?NCA7BTkqC3V6vpf^>oK{d~x}c$qKSgN8EGxoN@U_o0w%@P9}}j&EZIa+t-RRUL5Ujc=mHqHluJYQmZ5 z4&7u7eO?Ukn;$Jjyi|r#=1a=!NCr$L-6P-P*tJmDz=uuVH^W};;w&f1< z7Xn2tI}M@bSXp^HL_Y9_(i`(iT2A8G11kv;PxIwO8i(m%_@}Rk(-|DXyML`|Fg|AS zwwXfLl@u^^X*KISV&lHCW7ov2_;Y+G{V9lBG*P6$SUJZ0DiEPvbTUhST}1`|=s8Re zEaVe8Y&BiYpv)xO?~55`STLD19wFRra=p*1BTX8wY1+%$E?OPA-H!q&^p8d-gqO1-9RaMDA^>kBb&&q5zB3F(Bf+tXlvy2O*K%;{ux3zKb4gi$TF64IDt@y$Q?4ORKyrbe zwUX5G8X-A}yE!LP)3hwNL#Hp}{Jd+8c1>cE{iNAyH|~`&xxO^iZCTdfpXP&2$(B;9 zjj>~H={F*ruENafGb{T?&8mruh8D}Y1Re`0D=jR8PxSgKaQ(tV=Jz$qcoH5@!YpRog5b`?ksD9_(iQ7V6l*i&Jw z4%#u}C`86LZXoJHCDziZx9-!YZ{{?5vD4 zf1Wo)+B!FWh$|yc?V1n;t03eJvyJv+OqULsCw}X*D}!?);u3IDhA!uFy#awgHIG=T zhbovo`HwP=<~{DH8&6t(cQFI-v$*mAnr(x@oo_|;XU(gR?~QNT*=2aGWd{4}>k|i31;rWjUySUEBK|33 z%;F#4Fs#^2j{135=&cIz>C)p1^R-6PE zKSq0^ey-)CqmTFWWi2~ysc~DN(%pOq$Uis@}x`Pj+!s@NY`{jj=& z4Sj9w=~meppw)9*B&ki`ye#LB^R$u{&)#mEW^iP$|NZcf%JD!3O`d@c`PbAVO2!|5 z;yfYU6sljC7S2h`k-k<(3Oe%D#e4q~cxjV7BXcv5^5c}}7;o`r9UoJ-=Gd=D%OF0H zUDsWz7FOH(l4oC5U*I(QUXef4to(VId)S-bjupXFpE#~p=qr*!m$Kl;vzx9uDB6}8 z2!Ui*;p`!~Slr8TD-U@2ZKG8oWtu+yF|o8wXC*chGSB_2+!U6w@Kd>USm72l+B>;#j0ugmjEG1<`5EXnj^ux01)T)uEuoaP+$n{j zP~tzrO{Ppk%OA0GYQsF8Nd5Zl6>xTGXG^F3S)2)aaaU4I+L;S|1kg&`+kp~%*UpMs zAt2v*iQj-5j1>d+2BxT2b>i-|apkA-$=oC&4#XmXcG633y%T(dT;^hZVySjH2jGoQ zu72xpLWB8;tc+eK=oW78KWn10OoJH-1*vwH_)ZOeMNiC?LznRorj@p?sMiB%Zl$&h zzhTsL%HQX*@DOzl4#v2(%k|Y>wH?88{_359@Y-Fb$zpL5aW8ie zM)p(~c7Pw{k-UYf9rY2Tb>prj;<|=vdl>4sVts)=c^;6ywyY|PlVIp;%9YVlCZls@ z$Y5N1z(c|pMNn7xRI=N>5No>hpk!1}Qgh%N2Tq*xoB<8${R?GD53}ofrGY*w1$iM# zfX@LVclht4#8humtq189B+Fa5X+ktw@t&B2W>#RBL!cU$T7q}$jqa}&#)4;UV96{A!Yx#(HN$@MGe%8o>v6z^0bsW{WpnL??_@BwyC}Y$h;L(;L6a&Pr5lS^ zVVY4jU_%}5Yf|mVEM zmDG+en>I>$_Le!8jVeu}84;+d3#KCDoVH+EvQ%)8F?VBWPI#n#Bi}|6jk8KkkC;&L z+Q%;=#;qK+8^IkeNd8#P;iZfJR2juE>=?|GbrJcA+0ij2cz|AsY9aY_TIiB$E^MYI zE3P-4{+iR)+|5;(hFo-pVfbS>{_({;8ZrQT_sD+Md?W}Fh{m7^p_TYV00EXU?MQxf zRiB`+GJK5u2ZMb&#-f~%KpG~EVH%CGfH{l&tzv|B>}^b&=+VBpSJKMg2ifC6b5c8# z!aZ{mg&;c)H~pasF-Ge8OEOOC`sy9YQ^}N=O-1Tt5p&N%kt@rP+8uU1`VoXz7Ysf& zXcn^yNK)n6c!Q7p$HE#~p{g>WruG9=hEI0L7Tmo0LkVTXcq$<(7s3wL3In(7EvC#3+&?4RYzfN%6vRh9#Bp%IaS&82sFp zNp%ExRTP>o>-uMfW1Mo2;R~h3Sr;)HW;HjBtFfP$PzBDUtJntjRd?X%hHutt`=#6V z(UV+82y-^nT~dFGw1LE%i|pjh>=hm{m6d+-mVL}Z86)Dc*51q5b7n|3S)QObQ@r_u zShH+jQ^@HWuSM5nyekYe5Bd5KsKPBh3^o5m*$-b&+!~NuO4;D4!?cl28Wd3)P`8C~ z@BG?EbRd30zKFn$r(bNdyTHh4qB)7OS9ksRe+IUtfT)PUUuYxUSr89Fn8z_Xf`;xv zI-1=@bm^$2fRvHu0i{i&F%HWVjrDx{8-Zfn%@wBix)QoZ;uoAnG&%DfJV=}((hG0o znjR@$2(xEG{8=ln4qfHuy6r`XKu#f=gW{j);^A~pyq$zL-0e?5oFFIZZo&$zpD=-z z4-yb%jkOW_0lf5Y$ZR_kc0XPWqCH(R-HeNSDA@&1;D0Ip38%+hkQ*);KoyJvG0++j z8|p^5m*N#7IN5X~)an9-bqb)MIlUAG;W4+7X(c8Q%X^%xb^J@xlmh8@@V7q^OjJ3z z#a@Il<1gY~H(r6rK;dx?v3x8I12|Z06&wREl+8_6D)DYJFu02nGbbxdb|GFKO<4k$26W#ukmqnU%7D9I!3Eox>MhU5|lmvE7 zha;}f$u|eW{k3-b=&H`M*e#j{(3^9k-|Q#ztRizW|3;@0T3 zTuP)7 zZklwq$XlrICAfT5j{v0Go@KyvbCV0%(>t!dmcYv~RiUOS-xa-)>i)P#nO&ZfX|a5f zKoma5s?5wlrMfz_p2^+hirDGS2;oMeZYL$t)zUH(DU%d!0>6=KuU(@m2@`QQ&jnb4 zoBAwqIN1vhj!6OM;48H6&`j>;-1ca;=gN318mq?IW@nG@!U_PaSD2F zQt1(D=|avB502tA-4$D^&#D#I)8lIfSbVhPd5xU7qN+S`zk9SPH2zI0J@Uhu9SJX$ zIbf*c)PhJk??#lyClv7u4#O*m@LAcV*3aC0k+UygKFZz$Wa_R;5Xvzl8`otZY@KXm zJ|bF$^+X!}9*$}Rg;woO^wjadW(rbhFV#2$O#XuBv0Xz39t4D`Lv2|o63rl9->sNy zjk$W{W0@Y7yv8S9^;aUX)Nv{h$pd7F^7wL6E)bcH$3|zjgNTmb?C0HseyqJffOSDJ zZZS8Jah!2&*5zbgHP?pAuo7(98t(i5VE5%ap-qDdAPlWta>0HK0yJ;#4YNbhraS!az17FC(GHV)7+tiw2LO z^x!_TZ?Dm9gN^L%h=@H0w&N@4kmmP4(YN1|1E z()~!Z>_EB@G$5^_8RwJ37f8t#cEap|b%qxpe6G@c2}cQmTYamv!qSTg(OZx<#-)b3 z%ik7H85M&IabYREjVkl(t0lIT(*(U1yJ|%#Y{)kk5KL!EEJ(jFJ%y-JPE_G1qbE^Q z1jMf&SVsw8Mlo0v%9wC)MFiu67_(CA*c@(yASy>u-h{Ka&FGTgTA)oa!ln87Q%feF zU8g~|yX7iymhRVVF001Vzev&uK{23T8rSK&EG*nB4XHH!K(<*faP80!H{#o&3 zge@Xws7SOwd}G3(x(LU>Kv7X4Fvpg9hFANXevFE~tphFHEaDOFD~JHe=)Yld4|fEX z^{+So9{`g;Y`=(*3oBZPIS3Ny2Ux_n7ttEV67Iq`O_bKvOtUCR+z|&{w4y;uWzm-V zK{)Fs@FD9Un_QTT=>|~gm69#1j0*oMLPs>cUNE$T8W08#S0Q; zWTsiM({UVHmD$8K?80UAq*#ky5-R|~sErjN&nA-@8DuN2&{Z)gG7`ug(2!Y4fG>^l zI*6S%ES9A}HK{-6AHsr|ggt*MI zf|m#&-X`PIV#<`4*7-Uh!dh6S=2-ytLL7QY^uG8LFaWSOiEhHtV#;P+ApUNT2p1Zc zN>lI%&-Y=sD7t{Xp-xhjWv{X>GqFmOLds%T+w*jIK=E?9Yf7abSAisE@pW2u zYIto}vqn{2BpleV+m>*VtDu~?p9tZFWGt1qSFEo@1GXI_3e%FD z^}*q;hui zHnkuQE;tYSY~Db&s%1BL5%xMA;$^5ldTq}k{YBua7!V=l(Llpz5!u|(nw_) zjJnT6WzxELr%l!xrzT&Vr%Ppb+ZUPI@+q|0sp8KVmQq#|eyhZ5Bt0gHr3Mn9o+J~i zat7!GI*+JId!qS`bw|%Dn!h$BARMedhfm7J7J z(_Hyin&U>c;SE(x)zN60Vr^?mhZvNs8x3rdd*hJ%vkq#7Uci+q_5$07OlGxhFH1{e zNh)NaYIaDI##rW)6-tK)8JTp|0vSrVGuo`A8)bM-vJDn)jZLpnDo|QAuWQFOI^u$? z6no<`!kS{1uDsGF<`U%m!U9`mD!4(5t92x@ILBT}8&=XyfQ71vblN40$_Xk;ij{j> z``{HYyWA+{lC_PjdLtUf+EbdLV|i&AX{Otzmi2?7R~p^19L}02yzrBhMB^)waM{;Z zatEdsvMWWtX5?Qw=}MLgkI^@RDq(3)J1B%_5lhZ3#G9})~6v-9ZjgQEp0f2;_Z6C@u*L4@H4 zZKLA2nwuX}rxGO?4MkQ|(o#B2;7$VPAI}l@#K)AC&<(m^$f>C$9aQHM@m01BI1onx zuJ+{#fmQ)nNj!MUCrtg-azN_50;+4zS7GQdmM*r%>A-_)0x3!Zlz|T$(aBPX z>8TrnQ?eIsyy8@#FBQdAeTj777EeWC#`Tpv2aFl*6gHgsZTq5Dn_hKIC==ryF^F9a zkA$%%IbJfg?2)RcPQ((lUoZUp_!tyux>%o=6WAh5;wJ#PT40LAK#Qq&FqSJ64m5_N zMH0kcma5&5Cq)v916H7K(GGmi(}cET&f$k*0Ft<`uqj9V63A;yOoQb83or>MYt z&awskqLT#kn0;x#S&s9qO`Ge3Zn#?b&BtmR3MWJipV|TrjSovHRy7bI6=RjBEmZiy zJn~wF?2>z9H&fydxPJp;L}+GB2_)2k>Ji@al>JbnP*;R7MlU3Sq6N2J9=DBIAO%~- zF?Bv5yc|SBWXQ%fb-6pl^sBw_Y)XA zN5nUN$h90e&AkoN%B*Ua?uV$*y(FgQqM~D)#nL3-T`4DZ;b!rCm=@#H;~C1o#5|v| zNn!RAZ$mU&^QYEFK!Y6&(C_lctqu{3qz^ZaNGE;cjx3YCgu*?j%U|Lb`QNc=Vb@`@ zv^|H@YtBEdz7ump_;?G6*Zd*b#j=3gk3j>j8q8w}Yuq}Y7`WE>gMTys0N>b8huCg( zQHM}-nV3D$Md;5AAX}8pYj#2W@RmDXNbiC@j3u1a9AXF&(5mD6$^QWF>`(AE8Lvk) z1T6k=`Ajxe1)!%cHTafpzb!obOt66S?kFJ*whEM`6JP)vNil!MdK1TbI-xUK#ds>S zhv@GpAv3eGi$Vg9z@kSqoxxU()of+1?q=glwTzK?GKzze-cW=N9Hca&IJcGC78fUJ z$stK}D#v6U%DpiN*5>P5dcyuAv0F_Nk$;MF#sPGi8U}2+e%O_mtw@qJRFQs& zX6*Eu&GnHT5vyCh%-kTl3`B(p zGs=jAAs`RL8+O5kK9-<$no>_uiP?9lqcs!})?r0CNpsNvb;9CixmlHwZdVmbrIC?P zgqKREApZoH42Ft!AL7tE?!pCYlQ6*j>D#jD7nei9G!OdF}tT;qWr4F=A|CI z&7zY;!kRacbyWIdDN>+aH5ZNCP#v+D=?{h4q>{M|KBs5jNYxV$<`dZ%4kyO=yGe5@ zNor}QJ`i)ukCGAom8n-x9Hj=Vktyt%WEwk3AthIp45)$wG~rmK}F zUkW7gTKOlsAyHOHP(+(cb$cuXY&4DzQmmm4RO)5NjfrgoF37#ma1I~CstRINwK;2R zr~@9{FtX`u9$fKpT@Rn>IzGg>n$B??npm9F;kBakLC}>wg$F7Qxja*}H*lNuM!fNn zWx${TDcqBkB;|fu`K2HYz*;+Fg^KFVDdMF1A}Wo8r75ibVXW1%QPSr|Fgmo`ebB_}Olt0?Wf8e+7} zor7Tsx2@3#%4qu#)Gfx8%cPs?lb8`dC!#rYl$wO`>qyS=N^abcWQ*q}ROc~I78LqKc5 zAt~B8p~?iQ!0XE!RHKoJlu@K)$H2-k5B&fH&w2tk)dJdD+#y?Ig3FO z_Ob{nR&d?c+;3}XZ}*h6{xI3u)|(ep?6Y>AIWoHGN_I0|98KP*Q z%bKP_M%W;F`NbpOLkX2wR~hk#2-1!a0>-%4j8MM!B=2m*hW zS<9{i-)jj4i`H6FPTcbmE}>ajZw@NiK?|zCOjH-8>>-}5VZ6G3_Jod?@R8YAY!TZF zP_&tI)>4jQ3^ltVioGx4L71!{_kV;3zYY@zI=V^hgHV?iU#_Ay!AjI3i|@&V$L(aE z;~nqIgoo`^p5qHSo>pFirrE)QtU-zy(@qgj?KG3ve+VJdMiV4jq%GKg2s4+J*tJ*P zDyGa0*NTRUf|R<6N%R-!eJBdPm@tCr&Y?9eb*nG{{{RTDX!}XHVv?D)zfj_yTJDWu zm7^I=+UANkicGg@Ur6p~{zZW#+FYM{+NoH$K;Ic6^#1^g^++X>;mj*gWe#-Nj%YZp zr6g%nCTELHon5!vbY{-F(N&TSj?!a>rEXSe?S(6HM#-b?HdSlYWK-&;4u=hrKm$0} zYBLKgDJwQoMqQEewh5Z2(lJzw?AyFtvuXuLqd4BG`e4EirOjH9Ac0^8adaxX@yN{%3SY?c+(aS)%_#^zTjZ98f3x?3ka#|l^dG~mpib_Bu7bTK0;Ee zneF)uvM*@gxuioIe*eg@r$9;rV?9)N}f9{YahY^dUL`S7M(eDAHor7GMJtY zGfF~=s) zr_3pQl;Q4&s4R@X-AlEIgC#5KjP&XE3Us(TpbrQfERmME?l83nl17dJ2Xrpd@>a14 z1vw~f1~Sva4+|X19)dZ-Ck(cN5X-8+PUyV%Rwco-S~2Zbb;hNs@)YqsHt7ftI5JK5 z#z}@WZ#O-TYqaGlwM-#}T|TK%5pz!oOgPv{GK*5jt-cyd@PopVGs>G{MZ`Skrn?KO zGUe2?q?M8*W;8{Km4}<7U5-!3>+4@J)f+tqlH`>Mi3KedX|Te{^@XE0949dHSAI(I zAlyMu3Hk=5mn7qv-=fg-F2vfV!a7W*QgA*p!;Z?xt6Z+mp}h6(N8=P6OD@#zH>os< zb1K4aw6+G^qWLkxOA5`*Gcf%my8A}xTDjKohHvTb1kKI6H2niwVa=-s6KR?(`v~xV zp;IakRHvpHS1Vy)GJb*2IN2)HhU=8|)7@69E_%S{87(t}E)bzM;%U@%F~%Nw7Ux6X z%6|``#ZYTYFL3V%1pT3x#XM^4dC_17QST{2`?$P53g5vZ+c6(7&gx&hd(EF(o8vI7dg4 zcsM-Flg>ULPO^)~(Tf^o!L^*@0LxpZGQ+}Zg~g{*obIxERkjFtOi;=F9JKWXL(GZE zCTips@&*fSZKg7#!d{81VNY2-YJ`=-R*n50uWAdR$s^~(R(Sg4KzUi=>zLM$2f(jJ zq>ljv{GM0+DA4YYj9(Y{cc0mw1MnHDfv5P`dzO9 z2jd?OUca;d005{}eT;nxkMG9hdzm(eQ)*PR<>bHoQbH#(o{=_G8ek zv5txNPp+>RQ56S%k@1at@^o~5(rd&=Cxf%Q>MeMPUyS@Y`u@XMde5S z5@Mk8fV$12WtZUUa@MIfJH#vbJTt0w>TURl=YJdca(_SBmax_KFylP$(l8=*-=s`# zACvT&GF3$$(198VrzGc5K>I=;@FUmhVqvV^8g-kIp-V7bRkDT=TwpH2nRGX zLJj9qLVnPN`0fj}{h0V#h74vDb0;_hFs_pugPIqiTK-mScBn&TXl{ZDy=k%bglfJu zgM0fj9v-4GQu#aJyn4Qoje+eHVfKzyme1M{)$JMK)`iV!8r>HWynZc(eJ||DbY_gF zj#gab1IH}yF`};mP?D<(vO98wSA{4Nx4lsd>=D%*Z7KYz`x&}z6h1Y7NWcZTy5=s1 zpFwD!&ccUKf)hh#_IFtJL*iFxKVoe6DdA6T=Rn>4yy&=!ogJZM*y*H+iV6^M z675VmZdCZkhth)auis*#(!YC){>+u zVYI0yVFg0sKSUprriXvz&kO$m-Hm<`;Oz?*(U)70{Kc?L!+-dMevRYM!Bll~XNFr? z%BO2H^MS%vn8gEx4v}fJ$yVfP@|D@fW#yPiLv0~0s3j=_AOPJNpmFQ^(e#H2s=X9& zgwiu^G>$bj>A<6H{A!~xROKPSOKr7&xZ##9sWj=cM3uUhz6JV3!#XYDHGy$9HfN2) zk~3@L+)_2fy42Fp)8#wEZYc}iMyQ+Pb$@i&WT7^GF{GZL~?nsnn+ zZp}R7Wi5?Fl2QVSNl~_~ue4e`vfz=Tyf3G25ZF@#*V6JS6;4;jDn-EC-vuc1$<dzxGk@D7$}jOi|{x}$i53}R+pkwm1*5iV566#IJVC?t)2wj(Zx^(FwkCwt6D+B z?$;cyDyG6pCub1j9}MZ&=7z!FmT~eg1`Y~1uZ2D_a+il#MLv@z0_ruH#E`_QPQU=o zYgLVsJ4pZ&7|A%xE>Wp>x%2RK(oWL?9dz`^wRj`kkI=;eoP=TtismVwx57N+-z94Q z0Jw&LAaxZhwj(rw?n7w0w37Z5tJZMz$k{D0@@A!vR%r_zy2r9L(v`1aXFO>RIy!IB z9@p>#;QOPDX~7dm)r?1hC{=32(^G}{$=L?nb<0k^lQLuDd}YZv`t%4V{(#3?vu1fqTCx^lz&2)WpXkN(&aTD4azhumcV_%mu;`#1r*$_ z<77jsr1GcC^Sj+4;L%H^X*&on17P}fE}AJTRLd0Ubh3vW(exV-HNN`}$Jk2gl&1mlq zOgdRcy4O!_MM~8dIf(M!u{R+pFbXSE6U){CSJ}2bm!zB0r2hcSqyGR1jjCbQ1d>5R z5bL*o$BX1c{O)^OVrkEU3IjKm<3*7g`KAC{9Z4oIf(vdK| zw|JBN@uhIitF4|BIQgWmz)vJv+5A!?B9U?Fge!<;_leBiJNl#0g*atgjtZ3~k(!@FPRlKzq_~?Lh&yA{73e!h&I>CBQB*n%l0OLY>w<0Km?OuBbyO;NhQeZ!lfv?^E}u0LbN?8qbx^4#JGM%ntckY z(Uf*pQJ{n~Fy42t$ZMqdp;7V!P1L7Vb|sy3otBSiI6>&jS4z4rt5TkqOY>|emPuS( zhuZ~71Nep0*r@Y7OqnN28JA4Dfv^ZhV8-++DMHeH4qQbi8lRPQG!6lr9N))y{(lkT z*#;)??J8WLNldmDhvpo~Af$^Bl!Yku>h#CnpOdzXFMlww{r>>w_Wu9~XTie&Iiu|q z(q*QOwN80Fx^YBUg}4C-`zh5=Xfdbljw-brrrLauMwK-fB-b;`?LXkWD~9yliR9#{ z(z0^Q%p;3ohQb?cacDUtcEvN5vdRh>QV_`4l%~+{hHjTI&Jf`bjb*0iRH^2s8w+6w zB#(hcTRP+B+Mf!VTWDKSR5eU1bB?T!xJO?VXsDcgHRRd!37;rAD^Xnp-Zvfyx;|$} zT25Q_X%tUVX_Bjb*57YgwXIylB!iLKPuY(+svIb*^9j_Hl9!enj;UAnnDw*V#iLdn z;OLB9ULVRBnsv#BuAN&;HcL(A&`5DZ_@k0loVgt^pp&`uN4(Ai{{ZfdAO6OV!ahsk z-=o|=qq$5wiR5LaXf(H0sR@oDu-j$Z6{6s8DGqxvzT++t(pXQ01_aS6(8`sFsZ*1# zyrOm5bp<9}BRg3^6Bib}^(}1f*M{zjPMG*Gx@f@;=0y`Iws4X2APxLmf>w4Bd;Rw{fXaGa?jh9+i+-a!0g<&qLX1l-5i z-sd+2Obx=SqmEg|Z`IjF6{$tbc`9WLl3Xr@Yil7_^aZwWgHf& zMIKa5@QlWjfblZ{q5F-9h?~;pI-CTmr!WGu=72xCKI`Fk?rjYT;Q8EVqxsp2&Ksu! z^+KII5~-`Z*$!D9kZH07uKCxR=2Wtufj$B_EuTuW|%mR7N< zq7(*c8>1&Te5}z$TILrqi?M9!_)47Oue*#e#nsnlPr}YVZ}glo>;9B|%RLm~%^l)e zy%J*;%~qtT@4qE3x%QTqA4&;AN<$!0V0wuSx4-5*kLbfcO`n5g0$Q83b1G}NTw zVpdUPT%o-{6uT2*r4kLY1ATsBaz0G=E3}b?bW5hH;&+UFktinMB7W2scxOXe1`-B{sdz zzeVHa?g$(da6X>6KxtbBVg=QusQ6{q#EFoaOKw>cYH1;AQWbt^8-{VQaKzv(qpl9R z0IOpBDCKr)uPHMw(@oST8+E%az?EDE(smx0&B}Rhi%K`M82gmk1;QA+3TXu6JS|GZ za}w1FWXro!l}p96mefc|P{MP0;pbPHel?L}{zxaH?fApar?2{3sTX0R2C23gk z)o(a*4lMV_-JazJh-jKZ(*7m$!w$(;=}4m$GR;kdyxLsjTjv0ww%5)+5x+XoyJ*u( zHQFSLLWfbAq)fJsDQl9LTPk%u1f+v#;;&uNN=aPal_gV^?0bj#C+KVbOfa|o*4N=3 z`6p;+{!B2p{nppv9x>N+!HpP^FQXsgB)qMuO=e>+_2bI>y`9FtVm2svY;c28gbuSrLDUvMA%Z8;TDvvbN zV9K&isuG|D$tNMS$Ita$A>%w-DdftgDy`O~o?2}uIZ}FI3tjoV#VCSrvnXz|O{)^2 zerA0kg3&s)Bur`%(|9Fo1-VNXLxtXwFO+&y!L!_{oWxXV3`eBu)a3w8AUcW-H7OHF zNz8H1EGQt6>V%RnnFio}EmQY0bRScuIVh@qWtSG6UR2dld}!+cf}8!DM5R((`xNpc z!R0ih9bID`nDvdL?|v8l<)w2%cxrbT;2NyfFvD_pa&|^#peLmo7bV_c33UkroIpt% zZEM>x_dK{h=<|fel&jb`9l2Lw)Y8pDob4`Y4Bbt*l(>a!AzH+xz@f6*is_A_pL0H4 zQS!ETwaGB~sx0)wVM&*BRQfgs<~?E4-?^Kj{SD}fyNd9Vt5a2qXl>w{yyI@NTh~Zk z!dp(`eY>L~;6I>@Il>ngRb(oYZ?`8aDC6@Ar?`|j(bh^3loFKza-w!@NsDB*k3Jux zPfNBOc3sAixk^a@!%aipBicPE`<2=?a{%He==FS9^=XL*-H~o)pwiker3xqtNMu|U z0hPyWd0oNlLyl>WPxvzc%ojs7T9O%^RI-3^66w0%QcZ{iHieLEMZ_yKQn8g2ZKgPO z$F&t-a)X2R4WZQQbMsi7$y4QBn|;Zen_8%Cv=ymF%#45p$Il!NI3H+7g-iI)jdrq@ zXq=5r2??aMQXVrIFIlx;CPvF|hhcI&-3rX-91ZpyN&l2m4aayPrw-z(*-x>xU_a-zKAxsTcB`Wo~y($JXO!fW^C8xjQ!3(;N=`<^0y`t=&KLgX zW**T7iYu7AM}mH)%{d%=#FX;GuQ1idve2ZYYb7Hx2)G&C*u@vzq`?&QX~K~D5RsPNi2WOIwWdv0xH0KQpCZEMr)IG1>kKf`b(G@N(t=V3@<{?dLC`O_^?~WQ zW=?-fRVtNszcA8P^){U`$)zP!KqVT$Ypp|Owz5Xtx5H}Sk0WH3q&P?yiFPLe)z(CM zucwc44+*Od&eb$aKTxLESZz)>MXAh(<)(-P@o8~DDYYGdsYN|D+a6a`i?nKt%|3Qj za+8vdsh8MwI;(BOk`$E<#1KWgqt2~O_eWhhplXv1IU%T&>YLwWS4D^yCOr?}o$g@I z>CXpKv7V4B^Eh7))KDLhr&G|LTQb41OQlN%Eu}*=# z)we5EUCuK7HWp3(&7)jBDMCERsWjQ)vCL%}#{~KC0Hm(F~tLLfd&Tf!oX_4+R@s= zJ6J##0Ep{#M-@k0b-)%!TdF%&`=g442C#rEcCGh8b#1x~RyrUGx}duYAf-J};zn67 zEbHus>Rs{>;!W~^K!}~vE-4ai(&Sw>Q-ufafbvA54U2_CqzC}ErW*;>I{i?R99t?O zNKp~OV{Z}Owc7!V3p_55R)?8 zoz)~n?BzwLlnZPW6W0*4t5JB|S~}>;Pv$a|P~TTAmV*F0Ah&?l&O1(b)KcAX*6f1o zM{7go1)(}Xt`FKTdvGU6Rpa|X?`kUCrJZl9>Lm!~khs5FAqaA@I~Z z7qDtia>g<3bdSp4En1E_s)f|Dm9deTd9&Mv89}b_&y^&g#HzbveDTl z+c6kro!V2B2$XYjV_h06(!GgOksxtJOzoU|+b~7qI*NvKZlAVcry_RO)v)P;88-|y zPL9ZV}+0ei))w;F?aNg zITZH}$T+3CM_fGc7crK){*-pQ&iHxc$8Wj-(_Kl~26%2RV^UYs9jvdUVb7D?9Z+6G zz2*$jA2u&RQoOrO%>1Rl{6araG5Lj|Nvv0CrvCt}xBmc$N9pQ1sWj8DnfbxtTH?nE zjVM@inCt^$B)pk}QB$)KH;E)>D)LEAt1q%& zX)kMCH_fm?>W^_F$}JP=8y8hH%YbEGt*enQ5L3|OAyx}PnQRemv3T`%G}3gHnUpFj zmuT}R97y7PSu0hcV(ep6#Mb?7L|VOiInN z(~}D#>QaeVPym|&mdo#p7Y2msZkokTo21EQI>G{7k)L(uoObuJn^8iEBVh!Lv&`je zPlX2#e0iV^EYvW(z7wNN(-PB9$xY6eg5PaP1e>Km8!K34(G;u??u2QtNpH=wg)~`9 z#4gGqE0|3=nWwm*qC!fntgmBkn;7U+WtR5pORohxW_Q}(^l856{U&CSf^haPr#!YM zrRO}IFqC8*ZNw>QC-_v^1Nh8p{0eFlHC_x@CTekI$(Io|tfRiuZvpoK9|&-|)0Ug` zt)nI|{xs2(_$HQWEk25pWG0%{btzt}VNM-f!BMu}Y<<1JBA+u#;FEwQXB4GOA*sD$ zy}8c5N8ChQ;^RdpxT(0xvy#~Pi`_%S*rJJ~JRZ#ouH`mabd{;pp?bQ?C+?{e=sd`e|Eh6?;!zkW9W2NXapGaj6vo!k8 z@1T-C=OStZx{7`+n&W9rk*a%r`=ondl80B0Wl(a@w)BvP+PFo1h? zM0oz3DD;fOX%&fv&`7dFWj2pssbbX0L3{iPGy5Vru`Pa7j=U0==5qQTPw=eK6P0cf zSn{l@sBAwvm7$UkH{g&h_eBaz2-T#uQ7=5g6>ODpdqty$mLj82_(kJ`HC&(N9IYi% za;zyq9|VlAX!(Y(rP-E)h@;8RYaNchgMYnLRW% zu3?Y?Qo7WVg?*^_-oK#?M(?^SDS{=G`N?XB$!&cshnUEtx>qGt!wo0N$3&l(y4N4sUo6f7&QbksdUYj)5fKx zC@Dw_wZchCNf))iJEJR_**>N}!y8R!gZBqKUyCJNLp5YdnJQkjtR~&&G;P0BoqKNx zF?Z0c!?SuGz|Xw3I`fn{C9P^VDp6qsl6zy!Z+2r%&sFiZ7SUvc*%CCCe6Lbr2PI6n z3Rnv3Lwe+Yp6riJbQ}Kw64(p=VUhm;XGBRyhyLhXgKzN5(pr|~uR7LW^>(A@lPuE~ z4FIKdnEDsp53%8qq`(D_Eo(peyHWFyLiZ{%ZI+Q`z_=cFA7eTe9+OtI#>EaOv_VS3%XXsqQVHj(Qu{3AM>U?(8JZ)Oi@6l)+8JcNYo{pnqk4~ zHnfE#_z@JP%xIO>scUxyt!g(?l&L~V=`nG`)ru`vOHzkBAvq~8X0>VVp>4I6N#+|2 zw?&~d^VP!_MF&D$B(csGWu8q>W_?pqEri)3S>PRPC#WTQzh*ww_Y%o9jVs*W;3@wA z_@9S9?G}j8m#{99<)!SUh0tf6N_N{><}cUr!sn}^8~cf3)r~9v0GOx$0OEcpl4IV@kbq^RzX8?*tVO177@%Y?9<8eP|>suc!MwYHK&EQNyOs<6o^ zNK%RFiJNKiDmLzZlBVTZo|Sr9Wu!kY@(XS>;zE+Nkz$e#L=bIg@q2=vkEC>M?vGP2 z?5x6+id}A{D${B=DMDI&Bp$(N_L@9n&>enT5__vI)MZt!#KtD8DGD16n|xpHh^o2A z`i>nL>|P?SO5uz@Q>@OYrb?eG?Az){xed00rCYcd@sCLU>rR=m4lVVeZZHd7CdnNw>o|q!PhhaDQj9=Vbd2ir7 zC6%nK`ASzZf5|E)z1na79dB<19>svKP=|4o@@mGU$zw$Jn{z4=3MLjxZ zT~g4VEwXMK8w7rrG)eye6*x2gWs?5@$V6{OIc{fF-0;uc8GNILwv&e#QUuhlK>q;v zHX_sRU+AV=O8hFRPgFpdr(uaFYpycxX>r6U4YE5!j-h{G#XsF27vZg>?7v!-{{UlR zHP3O|7Rll66P0R2GRqeEI7#u(Xc zq2*C2uFW>no{NrwX3~0!%13;7rG)*_tu|3Kl`D#8@x1j?P)!GBsL$&1H(J)`w3dLf z2Ccv;u^Ai3uv{|mEdG*sE@>kVQkh)EN@|j~CD?3TPOYUS(116S#oN9=JhVJNKZz@{ zG)W0pCTerD2$f=82_A8(2o08@z+Q;d>k5ZJySawRF(o*z|N>vY`Di;cE z#03C*LZit%34W#!v#%MrXdl@939 znV!dKTL+^^Iy1!>ZN!!NPMrL*K>BJy2|m@Maj`E(AsLe4T-nXb* zL2+Zn)JN7@6vwS;M?_dV7Bb**HHuuk+LR6X>Oj{Wp;sNz8=)-~Q?wU=XDG}mrlr+W zs8wEcWRM=1an#)Y<7Ei!L{N+TwDh$4rV}pvZtMF!pWiXDNbcduy)Y_iKQgqpEKsn8sWV)4~x31r@2xedIl4E&{ z8^ISDGbFVlcD9!2?dpq?hg3Mx-q3J&$IG7LWj5WgerqZ!S)z$=F+`9h&+Y9@! zT78_twfqBtsY^j9W$MK87M);9h-rb;KuiA6*}hZUa?%Au9Is1ac`TtaiKGV7$~8wj zmfrrzgSa1J@Uhdl;OU`yo-a#DdTc(-l&D&Dke6Ilf|NP{3O&F_$66QR>5Xc7WWiMV z`lEQ03}QLdQ|6jnst~zlxsn`hNCMVft_{H#*lb3t?zl`UUxEzLPpw;$N$k4+00{FR zfzp^|}_bxGn(_AlTbR?ky zS@!BHS=HxVGVYO_HZ$3rd5b0R76!yvo^7=|D@CVF)Shh~l90F@+46=Ad0gyuSt~@ zrR{dxb;J|6D5*mIaqb?0f8sw!-}HV%{hblyUkN=Kv!-u#BBO$4oLf?rip+}>3vbd4 ziB^>5y7dyMQddKZvApQ>-Coj0kP>BZzXzxB5}E;^nl$U~A+v0O371eATPujputpBy z=Z|!yC5WAW70{V>c@MmbrAZQW_8Qk3$ug=~1ppgrrLsuf9;3@sFqVLHT{J0Fsd^R_ z!?F&{nMnpf2x+txsDLw4jfo`YNx3=4oA|%onZ!7Pw8bv~XzoTxOiU(SnX25<=A2kk zf(Dg;FekmMgsdH3oYV5xIM}$~Xoh?ZBPvvB#8cPz)X(>&% z+C_p=CyjuQc4SuTvNG#@YP_b>RxN8P+5Pe1jTJxrsfqsp^)-L(#v2kn)sF`K&0qdK zG=KhftN#F}O~<^E;NQ8ef6LcL{Tyvq{{T*#f%QO-X!t_^0K_(tf9Ul80Q)-Q^Ivfv zr4A6^@e8DH`aM7X&ba*7TH8bnXfPrM;t7{T7#^sCkRXT~hypG$5C9uMFxLh;;s^z! zjn2pbS6MdM1W|xI)Rcal9jAIY>mRJ6a8^ z0mYj~N-zUj1_M`ga7De$xaDZMnt1oNUJ%Te>O3B|a z?H!4cNM3&eusa~Dqq(#;uLy=X+N-N>Fk7%fXBSk6_|LdT%MVv^SrdYg@fQsr2m?uc z8y1vLWI>EwQ%JCP?hqb!)V{ku!4HS2xj9ihDDSA-iC2UQsE+Steh~sOeNb$B?hrnA z)ep}b_6U4EUB{IZN~E}i{9AzZS_mYZSIxLc>WGnxDun!Z_D3fbRMI{>Z%~7Wsuo1D zfHk%Cm8!D1;^IST9GYU* zH?@p?(WNX^M;bH5+LdV)FUb>nsZ7cVCy8Bv&O9bXK~9A!DLS{YSUJOYrqreLR#ntv zN#UZ}ceRYE<0ll>Tim_j%^*!-d{aoS%DJsIOr2(Rl&dgS+QQR*^oaI%M4ElUI%mTY zwR}HalW}e!7vvmyDVUaBvqI2pMUMMe?F5MM)}KSFRoqV_lv|x-McRp>y1VlYOg}Zq z0m$kq%JC6ZXzMOrh@psd9iMa1FLZxL*h$R>yLyMB1>!j~8SrEi|V&3yM7SC=B?rZmWQ7ZIUoG|3IF`6b2qqlb!hDsUNRkoj5YTcd5 z*&b!4w>HMIn|a2;$m%Sn{t(6bqt68uIHyV4mshN>6C7MRe3ZEzYZET6D(3ORb5BxQ zUaHB-(~#hxQ&v{T9*Y;0@;Xf(RKb_NmtZ(s;Am*#InO3baRF-6P72L!#+ET&vp<`HVI5)P9VI0p1Zn8Gx z7igR3x_^%G9UDlvK2ruswKl`FvbW}?QXJyd$EaJIkjpsqQjLhIzDAHPRHXv=hV`!c z2703VrC zI9BYM`HY`l5?89{Mi^Ay0NWQMUT>k*JGvWUL zQNI%H@|#Tl9-K$I%++C;V2UC!OD+kt02v745-+W?*N;_niC(5mX#W5cG~G%~ZaGYv zN>Z25NhPHK265rs#|c^qO_NW5yZ-=qK=72Jl-tR!+qM@B{E)brc$uz_Br&FpG>M0C zbuyVW-1Qcq%=<+sIhNKHs(Oe75xf&0psIeGuypnam&Cqbry^b2dTIrQO|~6MOMGUb zMeY;^R@;1|#3XQ*q6FB}o*jle@|vThr>s0A258!!s>Jp7S)ecDuLZ3(}P+nnr{xE;aXAf)=vmOyVET5?Y#Xl3!{{V8wM-nw4u(?`@k)3~;k6>lmU{mH!vZ)-VRK-qSG7k%bAyL=wa3K%ljlWf z{{RwSDn!ly0L>~s{r4cT-9tyZPQ`dOywd6Py7Y*gmUd&9fi%JNZgS@~wV(82Ft<2J z;bkiPmGC-|{xDI(FA4tuG=JFt02pfx`iI2dvFm3Hyb(szZw9P$h7maQ60?srW-_%1?v-7o%b- zr9JwE7GkW;I)9TOt=1WF3;0lx>1wGdByShCc8QH2$Y|BJT*NpoOAJd2l0&Z4Xv|Br zsf*`ztpE~p&s#Xf{n3nHPr*DNTd35KrzO0vF5QqWZc^pHvOLI^;VXru?i)uRlx-%& zi$|J%=anL>P2rD#Diuk0rKQsR%AJ{+1t|o}JDE}GC+~+z;T?m5%DFq2JNUoxg%QFx z2IdP6`w^nSxjVTcRx9+g*v&cDY13L2$E?fLWgUIW4DuU7A4yV_SXclH=5HUJS1_I> zd(x%Np4OH4N7Jrwj=|OmOAir$p#>ZxaA_l6UF-ECDd4ZxNERyIlWO-IWTvprl`;FZ zmi(I2lva}3=DrLl@!;4MTKPxTKIzosHQoq#l1`U0#Ps5)B+6KqaVuE?_77pH|X~f^sHTObr zy{zRF6_uq7A<#AI^>cSbp*gya1eW2zP|!}RHyYQ-XH6H?A8 zl@ygE`YIdJMZp`vF|-~MxJ^dWo9z{-|>mz7kMI9^utA|W~9J`66I!{U4{jfp8eu^)vPjp}X z`eL|sh;K$`dMz(b4i5m`Ij3jta(ymXFoXcj&Tsra|x6rWrp-!qrBbZ4acCD9Snj0{N0met9Icb%<(8S0<-C;7;9C9HVQT;W{ig$Y^H*OFvMRY4&JREx3g~kW!$+ z0R&&BJf`6#JzvrHxk;$Cb3nWqxFNqYq=|ebB;9&XS=w}(W?Y+iymkq8R<#71pHAG(w-M$0TqW;dR8KRC<)vEM+bwMG8Jxcf>S`K5 zRD+pxS`~AJH8>??)7GMP8x64dcKt%~cp9rz zmlBlrU8$EJbn2x#)cK^Q zLDQhDV6BoQ_QsF-Q?+l=rtl+$OJHYBCLavEhr~-`I2s4W1pI~s=o=SbCs@MKZ5L3da?xl|y zmxld8uRjuoodDwHeykx+$?F%WUy~-?v2+|N+#4xl#su)Kbc-5VObZOV$Tj8SQokph zT9I=spK1VbdBv+ACr^xB6~e9M0sNGVpcTTlV2{yF4#=(+K0&W7ig)DWj5djMdr%{T zo-fr0h)-RNTmJwm*}H1_F|Z(`g=F9s6xPMILg8WFLBv$pseVqlu;;}N^8$D{V$t&` zBc}0f{HteeZzncKTo~}MpHR1xn;n7|3lAZ26*ejZgN7|XFp=K|{G2go)T72Nf0cDW ze$Q<6K~D#<*`~E9I;s*f46iP<3Egd8+{g|9t`zk5nh zY>?c+Fx=?=m8tW4R$dvy8d~F|y*W2!hbYM|ag{eGV zv6py2qYYAmZkAnFY+Pn0SPHO`Qj^gLs(lC{DW)nnSo+O$GjyVg{W}lS3+W1yTB2F} zCrEH886_Z$&T%OtKW9=AO;zs?ou69J@{EdtgmcdyUpFt@+7uyfWlcCXguh9b1Ru;w z8@V7UC#=N7m0$wDlgh2v2sK^RNhzgVo$4{HF<6-p;YktR_mrdzfmeJpe*#D*_G}w< z#Ix9$?Kb?x~?v4Efz)MIfwEz)(3ndYA$7Y zDRiku+~c-7AzFRRTw&O(D+Htt_Hq=q*ImNE4q*~S=kyMpFi6qifv4-1DvU=~fGdk9iag5uF3YA7z z=G<6EtxFG5NjY*nnz)$8>L$v~dk$c!R7v6LJf%1?ol@!&3fI?rMMn^64q~WCn0&ZW zd8V_r)+?kyFBh{r!FkKHSb*Db&fl|#5)g2j<>~q>rxhT1U<*%&(sJc-D4xMsBQA z{HWDYovk)on^O{vB`r!e!2-!cDbCQ7(+gS^td+E}otKnT92mjmD5hrP)poF%k-aSf zZxrO{MtBmb+2b^$w5h{rkd@Ivlt>Aakz1RTv3QM1wQCy25MH7-t-?--%Zf!hk2N+& zqN|WUvMcj?f5kN*MKcPm2XlqBEBm8Fm%-JkOCb$NGM&W?i5Pv*Isscx1&c$eVYjw&j=!ioXfTv0J5#|1jlkHgQQzU#*B-WJ7+ z+g;U#JkP|J=T^z@i@hc3V$_rFj9OQMa+IJRtPB3@f8!621sMj-msoV3rpMzN^LRTD zjKz0W6PUsHg*@Y3z2dV|YU%{uP5j14I4)A#JnD<;>_CU|oERu7_{pi2b=U~doWacrsyxTj3`2+07AuRuQb~{3PFij{KPL&F#lc4&fRA!SzLuqh49R(*FS3 z46GSax9Qbiwhc)5j?(fo^TC4*0rH8V+#xf;gAHE7YGb?z(1r}C-}Kwxd)Gv^wkvuMR`BB9X*FQ zO;op2`)XkL#JaTKCj?TZQ9G%#SJSqTvA+o15}YTDYjRG~Q#9P>tdxRTUl@R(o_4Xz zoN|wze7}aPSD6CYo`DHhrnx90w5m6EGPI5f z6lE&jQ+GV}C-H-$f;|mn0abeUwT`I%_-R(gf|$2bDzj4!vTR)Fh{fqnO~kEAsm?gG z+Q=C~c&cmATcbYGEDrEQp|`3HSl&tUx5J^uyw*_zOaQMAzhzLJe`gSy60lI>`KBj&M-J+|VmZ z%xetOnDK~O&LgGL9w-%QwYjVjstL3qhx~<#KXZ2QJ0ZEI4j|> zKTNFkT|bNHJ_nCW;8#Stqck@r(GtRPFN<9@&B%3rj(DzhDy2BqMqGf#sOR# z@X$F{$scF&i_pOo#QM*lwqSh8rhk|3S%X!0pv(0rgM*eC-&!NRKa2?ASw39b+LMo9{CV!On$HY}9b{qTc22*Pti zS(?I@-_iv+{qcCOV2UF&upJI53OSu~lr2labO$97$`Ep3svRB)Xc6xYFNMCu!J zjAhy{qEeQNI5FdweQNom2OfcbR&YCO_f?v0Bsh9lc4+$s-&v2 zy=!H&BNrM*8KbUT4oXw2ys9Nm6{HbE}KEUe9RFCFEz`&|ou`VlfH%^4`L0JZ>ty}bn<>+SvC3>Q$vN~=f zN%L-)22x|j0AaddImr(gt#6_yFVxOcp?nN~X|KdVm7#13pV~|D5u=PhOCPBZ7!^=y zWPFi6Flzk~8D8daG&O*~q?|p3M|;iSB>vEF_lVIEK&66zG*65uC=`?WqI_ZVI0TQDI!|bgAIMa}woNwefD}q+t0F*GK zdVL;*{HfAYMnc>k!kCFwSaa}hssx(`p%Y0(bd}tz* zOh~bmMsNm|O;75Gg{<~M$WT4(G<&$L_s0zxX!IPy&wO9gOQ&1ph=U@VA{EV(O}e1g zdm-c~KK8mg*=61iG;O1#i`hg)_)}zg*OMLM3@LQ&L3viK`!jg6{F1_<~WBtpy|=xk3uqKe`rRH$fYmxR=b28%1Ubd znH~_GR{J8XjL*ysAA|B`tFk!YO&^SmqV3aY(gduaKPE?nah8+^qc<26 zN2m2w_&|&YqyGTruG^?ajAi9_N~6L!OH142?T+Y|RgFa%(7@V12PrpI)vE>=CjbxG z?|U(znR#^l!aIZ+EXwa;9uYdSFDgDi^SXGO@yaF_YZy+X8$P7>#0irr-aKH2SdISx ze0;8j7ug=pq_-^1;>ojeX4C=5f?>y<(;A^XaZ-9NVw_u0{{Y?qIHZiWM7$*@*rirW zxqO$!E-Zt}6oNY9URq^U6zeXcL5#T*3J0nrWh!cAK&5)U@yk~Nt$1=ajd$GAouO*8 z#tN#h(Rhw_USSL7)D(N-yXOM6N5bEzm~6W1g;}|N$m50nnBHR=lqyD7x7cc`wXR1wDK<*2 zHlg;6GjdjGAbxhEZ{CT!%Q{Kp+5rCa85HRfEV-8Tk3yq$TQ61iGig5MRZUHkoWhUV zgp|z6ZVbYQ+KZ|%?J3oMkZnI|7Df%Fx-zM>J5?HS)Z^FoBTchEDR>W*FUAusICJF+ zzwt(hGOaQJXVz)0fU+elS$Dva521U)8za z8gg_`Afh#EvbprC7*zCqEka3|a;Ylv5tvF zUT~dOPPWosn4gzzvPHs{1bqZC3f4!7JT#lQl(jL}?uL-1Ec(`o`c94Jr>vKc6ocz3 zEmX>`9j7FJC`#lu>j-r2I-rL2O-+KnrGfqNvaK6)7KFPIvRXK$($Y(-GcFClgq;LmXQ}y@g^}kK!MUcb!y4W#xHe_J`vasddekp=D%=HN2%LlC>Mc4i1H7 z(F~o%)C7W`E3vFP2>f9KjIi2L3aadtc8|s;>GfcvBuSO?KqP<-C%(&cc=C)E=rwGaYFh=3Bu=m4&pS|E;?aI04WqS3ch zG=EIkT<7HkcL+{#+)fgGi&|;RIjcU?3#LU1wz07hMOKqTWnu+#I3iPK(SM3FRCL!V@v7(@DD66CuW{YpRj+m>mTCs7kdt((kOrezLP;j24 z7$UTfLL;3v;q6I`9d3MsN13fZTxA?Se+!$if&$aFWfLH(q12IUB{jT<}89@br@+H zQt?VP?W#xvC`EXqop9MU*%`Z9O2h7`s5ttqvdx$kX)=g~SP6sn3`3~O(_0!7xUK&H zRka9g<|dn7U|Y5*p82#}`ZFHEfL@Ylsy>6~wFVQL8iHMm!t2wdSP%)`Ar~sM?h6-H z6yv0-DFAVAcObzIlIX+c=1dvGE(ORg=GGuV zt_JfIlcefkSIFkQg9GoKP5xyy>_Kp`buM%$U#!8--u>wYOxiD{i zDtT3nK5&kWSY)g0IIL*eTD3H;Q8MBsN!HYC0h}~*LzIV-RNKxa-GJq?7i&r~Lg&e| zhp46%MwDdlaY~!k=+%YDtFgNDAxL-vX5LDa08zMw>6#j($WJO^PrB-@Ym*AANz$kR zLX|kI^X9@n`%;Til4$e2$%rRBcj5v_YB#uSv%9VVV!Qz}}Ua1JwE z=4}KTP++3X(q|FWMehb)lUh(VqRo;;i6SSEb0w)*F^Xj4uBGK6g>!-d-xIBqy+qq& zQjU_)LHiSo*GUHe2A&s;*h(}$IpNf9B;ys2XOF3?iD>|NrNoN0;dZ9o8Z z+6r-&DD`L{cZhug&6k9@pgnHr9yMRSJ7S1&ZY*%$$cXPSBNO7|vWC}rhj7YWiu2ok z=sFZm`yPu$5m<*9IBn#4boauDtYZ)_FgN!TqE(Kn6` zVTn}78Ju!RHkC<$lHWAZn3QoQ!D<#6MIMWz`MPxTvr^U7^^h0^N1npJyx5ft9N2XG9QHru@xZv}AvcMfWrzj|)V>N3J zF0?;};Fzn&VJq%j*rlRN;L)t4h&L4BQL9p=U@--uENd_!dy zo+W9_l_#z^C0|IM(-d@JOi)P&68j*>93hCkY)0YiFuI7m^O3*rfK}`WIq$Sm4iK&@ zZY6i`j`K3IEv<=Ox9;8xFfPQ{Z7@<#LcZvwoEudmJWDb6!43$iA4?HFuJZ+lbY0P` zNz3mLWg&LhJJceKj0ZS>Z%huH%pBl152st2S7M9;KW+fMi+3K{KUibh5y_ir zIr64c*s&EeqsmggdTZN&8absC@sFr}^2{*3%W0pM8)q8tSc00Il0}s}E(h^NU})}& zpGZ1S@t?*xUs(fj0HNO|UAIAB_`%bF zXeVr<)!M)Dg7ywYgyITXKqjdxex<=?tsD$$df|P%G1SDFn!S9HbU`#p{en^C%?<&as@KJ;C)vk#) zRtN8Yj29J=A?L0iN{CfetMx#6>xb+~t2YgN%){;~$fvSS@dB(HLPpASId;LAt07fm ztUjMcs*k_$f}DMa(le=~_9XrgRN*=<>RSd5oHa;FY$=k$+lpYl!pR9QNLYCz^oTu) zKZF!%7Y~0tQohOjA!CQ>BQGV(cP0!dRHS~(mlyrm1<3hXbmVSIk8~5sTG@m-8U(#k zfT7Mnygfx%4x?yE5%BLFQa{UQw4)c?&Dz7I?V9Q9FyR<6=M~L4MwE)i7$~s`5VKY6 zG}3Rz4$PyTUlGK5X}@DtP8*rKcnRaS_J_@A*r@=Q2r;0si!kC(#zTeT>@uWSyKc)z zG`=B>Z2Lm&Gx! z`EoW?DET8T8ak6rii@J~=xE+WBPF_f<3wIE!%pR>k>LgyyAC&y2|eO6e-OsMOp4K? zx+o3c2?p#IUd|skqv}e4x*t99ZF?Hw{D1=X*_1PL9?{u6*0rKIoNW3=L&-&VL?F@C z8B0xz;C8_(`ZuGQ6^4}QUf`pgO${VdHLh3?Md<>X^0Ht9{m?3y^(6lQFxsPQaxrR# z7iwK-tl6;Gv0>QM5LqG87T3Jre6}C32K8`TcO_GTvlqX>;$i@YM@e*mlNh(k| z<|A36<4~%4QWt9-y4lCMtkk(P4J6TZI3ErHZbSaGH-7_RkUl_3KfMrZ#m$lqxg&o% z5?(Gs$1zv$&N_8&b2@el+!Cfa`EUS5Rp=s%?OJc)|F^W+B0jjvK?{F-{uaysV&$ z!&rS^vs?C|xvI$o-BlTIdP{@xfHjI@GgVex^#zZ{9&&OHJk_9D;+)sD2`>xK_fs1k z@SmJCRQgqEan-CNhAW^qa;mc@_)Hnck&Cy6D0}IRc*2Rpv^1a5%#qs>=Nr%vuhM8R zMPs}=6@Mrvt{!paWWp#EC1vE+L>(A*hkwz{L?^x;9Bo(Sz>c8;G?Rx$$>ZS$VPq%# z+M?g|b1-iKjA3aC@teJaf; zZ8^e&OE^v9l$n*>Z?qm`NLVVMr1F)a^#NdANH&8q9#&A5r93&upZGkW&g6j>oH1Uf z;ukVvv7T_jG>F=XlFl_uInudJc8 z!pw%E%XSLIG)mf3nR;Ry3eTP|c)B85OoXX2Y;4ac$?zRh3gJ0q2de6I?Ot&R$R2?g zQKeiW-H4o8t~1IE$TF5rM^V&66E}qj|hVrO~WF@&I@mYCrLP6S3I}~S&*`_bW6*R)mZR_62z$e zRg>5v0UAfcOBUtBw&D~TLBl?^K_k3DnFdx)2H6+1qjv0oOKhC^Gh@0Slcbz4a-Lp~ z7*RSw!v`Tz1F(oQA!KCHX{-F5zX(vY)raQo_(Te{gN6s~A>KrA(k>TTa;czOt{u>{ z*qC8<;21Z!a z>D-UHIWrCrZUI)+*!fnpK z2soT|Jw6duR+KQX**K^v(vBG$XBGEBoH8=o%bZryd>}bfr`A3ZQuooq+c|0Pf%nnF z2p=rCg`Je5%W0Wi@=@@Cr@1ceO3gyP#5N~~4E^Ybg@QTidm6pRW=hIh& z4<5dg6+xw3EI(Z^2TOQWC*>r;of6{9YFt?t=NJO(fcn5iPv2_`os&dB9V}sjN9RV+ zXGN&83a;{C)EaYPDWig#USigd>FW+W0z!7 z#+LBXjrl^LQ>FYWqnqp29Z<9EEQQ6%g>jjU(cEp$V<@IMrVK7r4;|;JAr(c*3+SWja*jEu?To&7i zkbTmpHmPx&moe$`H3n)etN@f`VO1)^;W0%{mT;;HKw7Rgl7xy$Rw{A~ zbjgNExl@+tg`6@n?n;ith$7UnYo@{}qfA&|={W$cG+~6_Hz8*XjJfNb;sGSzIHrv< z;g=KXx(pZJj}4z)L%Iy?c^P$ZePrn`;*4m}QsM8i4zDiIKXBI|W!os$Q zVrELR$YUMJ9B{7P4bFJ(*_*XBo+2Sk)~`mtiBN>L7aIRcMCSz0F|4ZqL=T>hepD( zAg*bj4xkGuaA#qWmu0NqWCt3d6rrYkIHY<@yb$S=4S{l}J0Q-*m6v`nC|tpiq{SQG zj}45{w=LHIG}DJtK)ao>S;vu=)TtrWT>Kh^uN7I`5aY8htWGH<({W?6BhHzy;cHV_ zXSNmh@zceDm9A zjKZ{wlVBw|z^!Suh3^#6raU-Pa#frc-**oj!qg$DBpGDOqIGp|dmfnWeQ#f6QWvI7 zJfB%+Iju2a;txGyD>@8}`NNG^&e6qgD>!>*)GSDj)M#a_Bg4$LI~B$n?q1o)Ypis` z!h{9npkPa=K{*2kZIN8YNpV-s;uc6M-v=sefv`cf+De6#A-D7wFgT?gwX=fpPG4`| z4mjq%lnP#M-jIy*J%gAGFy^vscJ;)=GLssYxVLOavoM4xC@5S+x+fb53fCIPbaGX4 z?2Th_w!><1lwOYFk$=rXWtD~ zGLfGfoDp+E*Dl+z#pRIhKLN{&sNOlnyY%6Rnb)vNl%*JXFG`!4u{Q}j%u7l<}NNQG50HNW2$mN|#zm(lU_ZO#9U7BzLu$^OT z-YluW@)Jl;D%Dp?fzB(e)Id&7fOkXmR9)i04*l`v*4A$Em5#V5E~?(crE05O$FMf|*q zdhzVqE)u}+gjJ+kn|U^rH}-E9*XUIF^`JP|1zXz|v{Las8eWk)rdo74ZSnLtd}J!T zsdG3dO~rEx{*Y^r8yTXJ`=AJH<}$1=Y~!9W7PbnBv?ivMnD!I7&tgG%o~YomryT6O zH&tSFM>(bVm}I1oV2TDSku6wqs+7q&%q;i7a_7`Db!WaAn~l-h#6-Csu6$aO|0v!e4d>dF=8HWrH8)z&s>PQfAXpQA0Y>p4O zcf^jwmo(*^8&Nq#V13BrFy~AGWJ&6Q1}F!7MG2=mU<|{AoZzro5`d&^$_H2z5dr1& z#|eer*UBp>695gjFtT=JVjZX4Rzl_+rN=dQh>NS(EIe?Lz7bJLRnFLC>#hy)&8co= zHp3N%#G^cgpg~7QR)*z=LT`|SR#uzb#N7;h76!;S7;Th9@vG^94=-inz?Ci%EqLxS z!y^%VYWiTo^^Nd^N$Xr~F~s%#@f;=(Oc=}(AOY~pI5xQvAIF}U?mqkAuo4=@M>8F3 zZ-xc#xDG$A9e{suAZ{Uun9FQ;9!~f{$a~)$RcL3%+k6#Izyq}|@KAHSGB4)^LY-U4{U#`8EW>isC#zZ?*@I z&ujobDm~BvP|J@!G2DM#06x}^))2#w>w)8sOdzoQC<6dpvE2-K{Pw|1moUP^@}PIY zf`mthPfQOVlmp~H3)RjzDL20Ok1rmW4n6@gM_nYq6(pEoAG8N3fJBD82~aT~$`4Ej zD1yvm@Ssd66gTE#FidL4a;}I05@l%{Ace&5h~obMTz4JU0LeZuZjR$3F)tgz`11

tsKoy8#$G{h%fh3ir2p%+bL~k8 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 Date: Thu, 2 Apr 2026 14:13:57 -0700 Subject: [PATCH 20/32] [Infra] Harden supply chain: remove unused scripts, add pip binary-only install Remove ci_cd/publish-proxy-extras.sh (dead, unreferenced PyPI publish script) and .pre-commit-config.yaml (pulls external repos from GitHub on git commit). Add --only-binary :all: to scripts/install.sh to prevent execution of malicious setup.py during pip install. Co-Authored-By: Claude Opus 4.6 (1M context) --- .pre-commit-config.yaml | 40 ----------------------------------- ci_cd/publish-proxy-extras.sh | 19 ----------------- scripts/install.sh | 4 ++-- 3 files changed, 2 insertions(+), 61 deletions(-) delete mode 100644 .pre-commit-config.yaml delete mode 100644 ci_cd/publish-proxy-extras.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 2bc361bc48f..00000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,40 +0,0 @@ -repos: -- repo: local - hooks: - - id: pyright - name: pyright - entry: pyright - language: system - types: [python] - files: ^(litellm/|litellm_proxy_extras/|enterprise/) - - id: isort - name: isort - entry: isort - language: system - types: [python] - files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py - exclude: ^litellm/__init__.py$ - - id: black - name: black - entry: poetry run black - language: system - types: [python] - files: (litellm/|litellm_proxy_extras/).*\.py -- repo: https://github.com/pycqa/flake8 - rev: 7.0.0 # The version of flake8 to use - hooks: - - id: flake8 - exclude: ^litellm/tests/|^litellm/proxy/tests/|^litellm/tests/test_litellm/|^tests/test_litellm/|^tests/enterprise/ - additional_dependencies: [flake8-print] - files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py -- repo: https://github.com/python-poetry/poetry - rev: 1.8.0 - hooks: - - id: poetry-check - files: ^(pyproject.toml|litellm-proxy-extras/pyproject.toml)$ -- repo: local - hooks: - - id: check-files-match - name: Check if files match - entry: python3 ci_cd/check_files_match.py - language: system \ No newline at end of file diff --git a/ci_cd/publish-proxy-extras.sh b/ci_cd/publish-proxy-extras.sh deleted file mode 100644 index 6c83d1f9212..00000000000 --- a/ci_cd/publish-proxy-extras.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Exit on error -set -e - -echo "🚀 Building and publishing litellm-proxy-extras" - -# Navigate to litellm-proxy-extras directory -cd "$(dirname "$0")/../litellm-proxy-extras" - -# Build the package -echo "📦 Building package..." -poetry build - -# Publish to PyPI -echo "🌎 Publishing to PyPI..." -poetry publish - -echo "✅ Done! Package published successfully" \ No newline at end of file diff --git a/scripts/install.sh b/scripts/install.sh index b9912287b70..03ae31cd18b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -83,8 +83,8 @@ echo "" header "Installing litellm[proxy]…" echo "" -"$PYTHON_BIN" -m pip install --upgrade "${LITELLM_PACKAGE}" \ - || die "pip install failed. Try manually: $PYTHON_BIN -m pip install '${LITELLM_PACKAGE}'" +"$PYTHON_BIN" -m pip install --only-binary :all: --upgrade "${LITELLM_PACKAGE}" \ + || die "pip install failed. Try manually: $PYTHON_BIN -m pip install --only-binary :all: '${LITELLM_PACKAGE}'" # ── find the litellm binary installed by pip for this Python ─────────────── # sysconfig.get_path('scripts') is where pip puts console scripts — reliable From 06df8edf922b6b08c70afbc4aa1cfa1f1ac46192 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Thu, 2 Apr 2026 15:18:24 -0700 Subject: [PATCH 21/32] docs: cleanup (#25026) --- docs/my-website/blog/april_townhall_announcement/index.md | 8 ++++++-- docs/my-website/docusaurus.config.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/my-website/blog/april_townhall_announcement/index.md b/docs/my-website/blog/april_townhall_announcement/index.md index b81f61bae62..466d9e845f0 100644 --- a/docs/my-website/blog/april_townhall_announcement/index.md +++ b/docs/my-website/blog/april_townhall_announcement/index.md @@ -1,10 +1,10 @@ --- slug: april-townhall-announcement -title: "April Townhall: Friday, 10 April at 7:30 AM" +title: "April Townhall: Security + Product Roadmap" date: 2026-04-02T07:30:00 authors: - krrish -description: "Join the LiteLLM April townhall on Friday, 10 April at 7:30 AM." +description: "Join the LiteLLM April townhall on Friday, 10 April at 7:30 AM to learn about LiteLLM's security and product roadmap." tags: [announcement, townhall] hide_table_of_contents: true --- @@ -26,6 +26,10 @@ We are hosting our April townhall on **Friday, 10 April at 7:30 AM PST**. - Reliability and security updates - Open Q&A with the team +## How to contribute + +Add your thoughts to this [ticket](https://github.com/BerriAI/litellm/issues/24825) to help us shape the agenda. + ## Register Register here: [LiteLLM April Townhall Form](https://forms.gle/hvyVXwbFjzJQE7dEA) diff --git a/docs/my-website/docusaurus.config.js b/docs/my-website/docusaurus.config.js index 81c08609e5d..0102d96ee6f 100644 --- a/docs/my-website/docusaurus.config.js +++ b/docs/my-website/docusaurus.config.js @@ -284,8 +284,8 @@ const config = { label: 'Enterprise', to: "docs/enterprise" }, + { to: '/release_notes', label: 'Changelog', position: 'left' }, { to: '/blog', label: 'Blog', position: 'left' }, - { to: '/release_notes', label: 'Release Notes', position: 'left' }, { href: 'https://github.com/BerriAI/litellm', position: 'right', From b7ccc5b691d90ecca83cf1b8ce12140022247634 Mon Sep 17 00:00:00 2001 From: David Chen Date: Thu, 2 Apr 2026 15:55:55 -0700 Subject: [PATCH 22/32] [Test Fix] fix gov pricing tests (#25022) * fix pricing tests * fix mypy * fix cost expectation since us based model is used now. * fix test get model info --- litellm/cost_calculator.py | 4 +- .../litellm_core_utils/llm_request_utils.py | 5 +- litellm/llms/azure_ai/cost_calculator.py | 2 +- litellm/llms/vertex_ai/cost_calculator.py | 4 +- ...odel_prices_and_context_window_backup.json | 66 ++++++++++++++++--- litellm/router.py | 8 +-- model_prices_and_context_window.json | 66 ++++++++++++++++--- .../llm_translation/test_bedrock_govcloud.py | 65 +++++++++--------- .../completion_with_bedrock_call.json | 2 +- 9 files changed, 161 insertions(+), 61 deletions(-) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index 29d28b8c896..3b73b853eca 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -545,8 +545,8 @@ def cost_per_token( # noqa: PLR0915 ) if ( - model_info.get("input_cost_per_token", 0) > 0 - or model_info.get("output_cost_per_token", 0) > 0 + (model_info.get("input_cost_per_token") or 0.0) > 0 + or (model_info.get("output_cost_per_token") or 0.0) > 0 ): return generic_cost_per_token( model=model, diff --git a/litellm/litellm_core_utils/llm_request_utils.py b/litellm/litellm_core_utils/llm_request_utils.py index a2292d6e00f..dc70069ac5a 100644 --- a/litellm/litellm_core_utils/llm_request_utils.py +++ b/litellm/litellm_core_utils/llm_request_utils.py @@ -56,9 +56,8 @@ def pick_cheapest_chat_models_from_llm_provider(custom_llm_provider: str, n=1): continue if model_info.get("mode") != "chat": continue - _cost = model_info.get("input_cost_per_token", 0) + model_info.get( - "output_cost_per_token", 0 - ) + _cost = (model_info.get("input_cost_per_token") or 0.0) + (model_info.get( + "output_cost_per_token") or 0.0) model_costs.append((model, _cost)) # Sort by cost (ascending) diff --git a/litellm/llms/azure_ai/cost_calculator.py b/litellm/llms/azure_ai/cost_calculator.py index 3cca61b2186..067181b946a 100644 --- a/litellm/llms/azure_ai/cost_calculator.py +++ b/litellm/llms/azure_ai/cost_calculator.py @@ -54,7 +54,7 @@ def calculate_azure_model_router_flat_cost(model: str, prompt_tokens: int) -> fl model_info = get_model_info(model="model_router", custom_llm_provider="azure_ai") router_flat_cost_per_token = model_info.get("input_cost_per_token", 0) - if router_flat_cost_per_token > 0: + if router_flat_cost_per_token and router_flat_cost_per_token > 0: return prompt_tokens * router_flat_cost_per_token return 0.0 diff --git a/litellm/llms/vertex_ai/cost_calculator.py b/litellm/llms/vertex_ai/cost_calculator.py index e7ac453e949..4ca3d29e7d2 100644 --- a/litellm/llms/vertex_ai/cost_calculator.py +++ b/litellm/llms/vertex_ai/cost_calculator.py @@ -203,7 +203,7 @@ def _handle_128k_pricing( ): prompt_cost = prompt_tokens * input_cost_per_token_above_128k_tokens else: - prompt_cost = prompt_tokens * model_info["input_cost_per_token"] + prompt_cost = prompt_tokens * (model_info["input_cost_per_token"] or 0.0) ## CALCULATE OUTPUT COST output_cost_per_token_above_128k_tokens = model_info.get( @@ -215,7 +215,7 @@ def _handle_128k_pricing( ): completion_cost = completion_tokens * output_cost_per_token_above_128k_tokens else: - completion_cost = completion_tokens * model_info["output_cost_per_token"] + completion_cost = completion_tokens * (model_info["output_cost_per_token"] or 0.0) return prompt_cost, completion_cost diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index d4f986edd9b..51b7b56a285 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -7643,13 +7643,13 @@ "cache_creation_input_token_cost": 3.75e-07 }, "bedrock/us-gov-east-1/claude-sonnet-4-5-20250929-v1:0": { - "input_cost_per_token": 3.3e-06, + "input_cost_per_token": 3.6e-06, "litellm_provider": "bedrock", "max_input_tokens": 200000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "output_cost_per_token": 1.65e-05, + "output_cost_per_token": 1.8e-05, "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, @@ -7659,8 +7659,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 3.3e-07, - "cache_creation_input_token_cost": 4.125e-06 + "cache_read_input_token_cost": 3.6e-07, + "cache_creation_input_token_cost": 4.5e-06 }, "bedrock/us-gov-east-1/meta.llama3-70b-instruct-v1:0": { "input_cost_per_token": 2.65e-06, @@ -7794,13 +7794,13 @@ "cache_creation_input_token_cost": 3.75e-07 }, "bedrock/us-gov-west-1/claude-sonnet-4-5-20250929-v1:0": { - "input_cost_per_token": 3.3e-06, + "input_cost_per_token": 3.6e-06, "litellm_provider": "bedrock", "max_input_tokens": 200000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "output_cost_per_token": 1.65e-05, + "output_cost_per_token": 1.8e-05, "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, @@ -7810,8 +7810,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 3.3e-07, - "cache_creation_input_token_cost": 4.125e-06 + "cache_read_input_token_cost": 3.6e-07, + "cache_creation_input_token_cost": 4.5e-06 }, "bedrock/us-gov-west-1/meta.llama3-70b-instruct-v1:0": { "input_cost_per_token": 2.65e-06, @@ -31164,7 +31164,9 @@ "mode": "chat", "output_cost_per_token": 3.2e-06, "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing#glm-models", - "supported_regions": ["global"], + "supported_regions": [ + "global" + ], "supports_function_calling": true, "supports_prompt_caching": true, "supports_reasoning": true, @@ -37473,5 +37475,51 @@ ] } ] + }, + "bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0": { + "cache_creation_input_token_cost": 1.5e-06, + "cache_read_input_token_cost": 1.2e-07, + "input_cost_per_token": 1.2e-06, + "litellm_provider": "bedrock", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://aws.amazon.com/about-aws/whats-new/2025/10/claude-4-5-haiku-anthropic-amazon-bedrock", + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "tool_use_system_prompt_tokens": 346, + "supports_native_structured_output": true, + "supports_pdf_input": true + }, + "bedrock/us-gov-west-1/anthropic.claude-haiku-4-5-20251001-v1:0": { + "cache_creation_input_token_cost": 1.5e-06, + "cache_read_input_token_cost": 1.2e-07, + "input_cost_per_token": 1.2e-06, + "litellm_provider": "bedrock", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://aws.amazon.com/about-aws/whats-new/2025/10/claude-4-5-haiku-anthropic-amazon-bedrock", + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "tool_use_system_prompt_tokens": 346, + "supports_native_structured_output": true, + "supports_pdf_input": true } } diff --git a/litellm/router.py b/litellm/router.py index 586d5961b94..1b8f7c91761 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -7856,16 +7856,16 @@ class Router: model_group_info.max_output_tokens = model_info["max_output_tokens"] if model_info.get("input_cost_per_token", None) is not None and ( model_group_info.input_cost_per_token is None - or model_info["input_cost_per_token"] - > model_group_info.input_cost_per_token + or (model_info["input_cost_per_token"] or 0.0) + > (model_group_info.input_cost_per_token or 0.0) ): model_group_info.input_cost_per_token = model_info[ "input_cost_per_token" ] if model_info.get("output_cost_per_token", None) is not None and ( model_group_info.output_cost_per_token is None - or model_info["output_cost_per_token"] - > model_group_info.output_cost_per_token + or (model_info["output_cost_per_token"] or 0.0) + > (model_group_info.output_cost_per_token or 0.0) ): model_group_info.output_cost_per_token = model_info[ "output_cost_per_token" diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index d4f986edd9b..51b7b56a285 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -7643,13 +7643,13 @@ "cache_creation_input_token_cost": 3.75e-07 }, "bedrock/us-gov-east-1/claude-sonnet-4-5-20250929-v1:0": { - "input_cost_per_token": 3.3e-06, + "input_cost_per_token": 3.6e-06, "litellm_provider": "bedrock", "max_input_tokens": 200000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "output_cost_per_token": 1.65e-05, + "output_cost_per_token": 1.8e-05, "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, @@ -7659,8 +7659,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 3.3e-07, - "cache_creation_input_token_cost": 4.125e-06 + "cache_read_input_token_cost": 3.6e-07, + "cache_creation_input_token_cost": 4.5e-06 }, "bedrock/us-gov-east-1/meta.llama3-70b-instruct-v1:0": { "input_cost_per_token": 2.65e-06, @@ -7794,13 +7794,13 @@ "cache_creation_input_token_cost": 3.75e-07 }, "bedrock/us-gov-west-1/claude-sonnet-4-5-20250929-v1:0": { - "input_cost_per_token": 3.3e-06, + "input_cost_per_token": 3.6e-06, "litellm_provider": "bedrock", "max_input_tokens": 200000, "max_output_tokens": 4096, "max_tokens": 4096, "mode": "chat", - "output_cost_per_token": 1.65e-05, + "output_cost_per_token": 1.8e-05, "supports_assistant_prefill": true, "supports_computer_use": true, "supports_function_calling": true, @@ -7810,8 +7810,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 3.3e-07, - "cache_creation_input_token_cost": 4.125e-06 + "cache_read_input_token_cost": 3.6e-07, + "cache_creation_input_token_cost": 4.5e-06 }, "bedrock/us-gov-west-1/meta.llama3-70b-instruct-v1:0": { "input_cost_per_token": 2.65e-06, @@ -31164,7 +31164,9 @@ "mode": "chat", "output_cost_per_token": 3.2e-06, "source": "https://cloud.google.com/vertex-ai/generative-ai/pricing#glm-models", - "supported_regions": ["global"], + "supported_regions": [ + "global" + ], "supports_function_calling": true, "supports_prompt_caching": true, "supports_reasoning": true, @@ -37473,5 +37475,51 @@ ] } ] + }, + "bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0": { + "cache_creation_input_token_cost": 1.5e-06, + "cache_read_input_token_cost": 1.2e-07, + "input_cost_per_token": 1.2e-06, + "litellm_provider": "bedrock", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://aws.amazon.com/about-aws/whats-new/2025/10/claude-4-5-haiku-anthropic-amazon-bedrock", + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "tool_use_system_prompt_tokens": 346, + "supports_native_structured_output": true, + "supports_pdf_input": true + }, + "bedrock/us-gov-west-1/anthropic.claude-haiku-4-5-20251001-v1:0": { + "cache_creation_input_token_cost": 1.5e-06, + "cache_read_input_token_cost": 1.2e-07, + "input_cost_per_token": 1.2e-06, + "litellm_provider": "bedrock", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "output_cost_per_token": 6e-06, + "source": "https://aws.amazon.com/about-aws/whats-new/2025/10/claude-4-5-haiku-anthropic-amazon-bedrock", + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true, + "tool_use_system_prompt_tokens": 346, + "supports_native_structured_output": true, + "supports_pdf_input": true } } diff --git a/tests/llm_translation/test_bedrock_govcloud.py b/tests/llm_translation/test_bedrock_govcloud.py index 4dbfa45a7de..456eac84a3f 100644 --- a/tests/llm_translation/test_bedrock_govcloud.py +++ b/tests/llm_translation/test_bedrock_govcloud.py @@ -198,35 +198,38 @@ class TestBedrockGovCloudSupport: from litellm.utils import Usage # Mock completion response for base model + # Use us.* inference profile ID to match us.* pricing ($1.10/$5.50 per MTok) base_model_response = ModelResponse( id="test-base", choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], created=1234567890, + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", + object="chat.completion", + system_fingerprint=None, + usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), + ) + base_model_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-east-1"} + + # Mock completion response for gov model + # GovCloud responses use base anthropic.* model ID; pricing is looked up + # via bedrock/us-gov-east-1/anthropic.* entries in model_cost + gov_model_response = ModelResponse( + id="test-gov", + choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], + created=1234567890, model="anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), ) - base_model_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-east-1"} - - # Mock completion response for gov model - gov_model_response = ModelResponse( - id="test-gov", - choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], - created=1234567890, - model="anthropic.claude-haiku-4-5-20251001-v1:0", # Same base model name - object="chat.completion", - system_fingerprint=None, - usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), - ) gov_model_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-gov-east-1"} - + # Mock completion response for gov-west model gov_west_model_response = ModelResponse( id="test-gov-west", choices=[Choices(finish_reason="stop", index=0, message=Message(content="Hello", role="assistant"))], created=1234567890, - model="anthropic.claude-haiku-4-5-20251001-v1:0", # Same base model name + model="anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15), @@ -237,25 +240,27 @@ class TestBedrockGovCloudSupport: messages = [{"role": "user", "content": "Hello, how are you?"}] # Calculate costs using the standard Bedrock format with region parameter + # Base model uses us.* inference profile — no region_name needed since + # the response model already contains the us.* prefix for pricing lookup. base_cost = completion_cost( model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=base_model_response, messages=messages, - region_name="us-east-1", # Standard region ) - + + # GovCloud models use region_name to look up bedrock/us-gov-*/anthropic.* pricing gov_east_cost = completion_cost( - model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", + model="bedrock/anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=gov_model_response, messages=messages, - region_name="us-gov-east-1", # Gov region + region_name="us-gov-east-1", ) - + gov_west_cost = completion_cost( - model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", + model="bedrock/anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=gov_west_model_response, messages=messages, - region_name="us-gov-west-1", # Gov region + region_name="us-gov-west-1", ) # Expected costs based on pricing: @@ -278,20 +283,19 @@ class TestBedrockGovCloudSupport: id="test-large", choices=[Choices(finish_reason="stop", index=0, message=Message(content="A longer response", role="assistant"))], created=1234567890, - model="anthropic.claude-haiku-4-5-20251001-v1:0", + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", object="chat.completion", system_fingerprint=None, usage=Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150), ) large_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-east-1"} - + large_base_cost = completion_cost( model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=large_response, messages=messages, - region_name="us-east-1", ) - + # Create large response for gov model large_gov_response = ModelResponse( id="test-large-gov", @@ -303,9 +307,9 @@ class TestBedrockGovCloudSupport: usage=Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150), ) large_gov_response._hidden_params = {"custom_llm_provider": "bedrock", "region_name": "us-gov-east-1"} - + large_gov_cost = completion_cost( - model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", + model="bedrock/anthropic.claude-haiku-4-5-20251001-v1:0", completion_response=large_gov_response, messages=messages, region_name="us-gov-east-1", @@ -379,15 +383,16 @@ class TestBedrockGovCloudSupport: ) # Test gov-east model completion + # GovCloud users specify the base anthropic.* model ID with the gov region gov_east_result = completion( - model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", + model="bedrock/anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello"}], aws_region_name="us-gov-east-1" ) - + # Test gov-west model completion gov_west_result = completion( - model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0", + model="bedrock/anthropic.claude-haiku-4-5-20251001-v1:0", messages=[{"role": "user", "content": "Hello"}], aws_region_name="us-gov-west-1" ) diff --git a/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json b/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json index b22336aecf7..dd49d9751f1 100644 --- a/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json +++ b/tests/logging_callback_tests/langfuse_expected_request_body/completion_with_bedrock_call.json @@ -62,7 +62,7 @@ "input": 10, "output": 10, "unit": "TOKENS", - "totalCost": 6.599999999999999e-05 + "totalCost": 6e-05 }, "usageDetails": { "input": 10, From 3ad953e75cc49535932695321cdf963f59e118cc Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 2 Apr 2026 16:10:32 -0700 Subject: [PATCH 23/32] =?UTF-8?q?bump:=20version=200.4.62=20=E2=86=92=200.?= =?UTF-8?q?4.63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litellm-proxy-extras/pyproject.toml | 4 ++-- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/litellm-proxy-extras/pyproject.toml b/litellm-proxy-extras/pyproject.toml index 55c964557fd..9946ac0af8c 100644 --- a/litellm-proxy-extras/pyproject.toml +++ b/litellm-proxy-extras/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm-proxy-extras" -version = "0.4.62" +version = "0.4.63" description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package." authors = ["BerriAI"] readme = "README.md" @@ -22,7 +22,7 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.commitizen] -version = "0.4.62" +version = "0.4.63" version_files = [ "pyproject.toml:version", "../requirements.txt:litellm-proxy-extras==", diff --git a/pyproject.toml b/pyproject.toml index 65d37804aca..ed9b0b8c57f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,7 @@ boto3 = { version = "1.42.80", optional = true } redisvl = {version = "0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"} mcp = {version = "1.26.0", optional = true, python = ">=3.10"} a2a-sdk = {version = "0.3.25", optional = true, python = ">=3.10"} -litellm-proxy-extras = {version = "0.4.62", optional = true} +litellm-proxy-extras = {version = "0.4.63", optional = true} rich = {version = "13.9.4", optional = true} litellm-enterprise = {version = "0.1.35", optional = true} diskcache = {version = "5.6.3", optional = true} diff --git a/requirements.txt b/requirements.txt index ab8d6bcd918..e42d4d54484 100644 --- a/requirements.txt +++ b/requirements.txt @@ -56,7 +56,7 @@ grpcio==1.80.0 sentry_sdk==2.21.0 # for sentry error handling detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests tzdata==2025.1 # IANA time zone database -litellm-proxy-extras==0.4.62 # for proxy extras - e.g. prisma migrations +litellm-proxy-extras==0.4.63 # for proxy extras - e.g. prisma migrations llm-sandbox==0.3.31 # for skill execution in sandbox ### LITELLM PACKAGE DEPENDENCIES python-dotenv==1.0.1 # for env From 3604b600d3fa6b0217c751ba9166f3fcbc5a24c7 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Thu, 2 Apr 2026 16:38:01 -0700 Subject: [PATCH 24/32] [Infra] Merge internal dev branch with main (#25036) * fix(proxy): enforce key-level model allowlist for custom auth custom_auth_run_common_checks only runs common_checks (team/user/project model checks). Custom auth now also enforces key-level model restrictions via can_key_call_model. Move the custom-auth key-access regression tests to test_user_api_key_auth.py and keep test_custom_auth_end_user_budget.py focused on end-user budget behavior. Made-with: Cursor * fix(proxy): gate custom-auth key model checks behind opt-in Keep key-level model allowlist enforcement in custom auth behind `custom_auth_run_common_checks` to preserve backwards compatibility, and update tests to verify default non-enforcement and opt-in enforcement behavior. Made-with: Cursor * test(proxy): isolate custom auth default check from shared settings state Patch `proxy_server.general_settings` to an empty dict in the default custom-auth key-access test so it remains deterministic under shared module state. Made-with: Cursor * test(proxy): strengthen custom auth post-check assertions Tighten custom auth regression tests by asserting exact can_key_call_model args and remove an unused common_checks mock from the default behavior path. Made-with: Cursor * fix(agentcore): parse A2A JSON-RPC responses in AgentCore provider * fix(prompt-templates): ensure_alternating_roles handles tool-call chains * feat(auth): add JWT claim routing overrides for OAuth2 validation Made-with: Cursor * docs(auth): document JWT-to-OAuth2 routing overrides Add generic docs for running JWT and OAuth2 together, including routing_overrides YAML examples and list-based selector behavior for iss/client_id/aud. Made-with: Cursor --------- Co-authored-by: Milan Co-authored-by: michelligabriele --- docs/my-website/docs/proxy/oauth2.md | 21 ++ docs/my-website/docs/proxy/token_auth.md | 41 +++ .../prompt_templates/common_utils.py | 29 +- .../bedrock/chat/agentcore/transformation.py | 14 + litellm/proxy/_types.py | 22 ++ litellm/proxy/auth/handle_jwt.py | 64 ++-- litellm/proxy/auth/user_api_key_auth.py | 183 ++++++++--- tests/llm_translation/test_prompt_factory.py | 186 ++++++++++- .../test_agentcore_transformation.py | 61 ++++ .../proxy/auth/test_user_api_key_auth.py | 295 +++++++++++++++++- 10 files changed, 829 insertions(+), 87 deletions(-) diff --git a/docs/my-website/docs/proxy/oauth2.md b/docs/my-website/docs/proxy/oauth2.md index 204a01538cc..c0597058cfd 100644 --- a/docs/my-website/docs/proxy/oauth2.md +++ b/docs/my-website/docs/proxy/oauth2.md @@ -61,3 +61,24 @@ curl --location 'http://0.0.0.0:4000/chat/completions' \ Start the LiteLLM Proxy with [`--detailed_debug` mode and you should see more verbose logs](cli.md#detailed_debug) +## Using OAuth2 + JWT Together + +If both `enable_oauth2_auth` and `enable_jwt_auth` are enabled, LiteLLM can split auth paths: +- JWT validation for user tokens +- OAuth2 introspection for machine tokens + +For JWT-shaped machine tokens, configure `litellm_jwtauth.routing_overrides`: + +```yaml title="config.yaml" +general_settings: + enable_jwt_auth: true + enable_oauth2_auth: true + litellm_jwtauth: + routing_overrides: + - iss: "machine-issuer.example.com" + client_id: "MID_LITELLM" + path: "oauth2" +``` + +For full `routing_overrides` behavior and list-based selectors, see [`/proxy/token_auth`](./token_auth.md#route-jwt-shaped-machine-tokens-to-oauth2). + diff --git a/docs/my-website/docs/proxy/token_auth.md b/docs/my-website/docs/proxy/token_auth.md index c287ab03644..d37b05391b6 100644 --- a/docs/my-website/docs/proxy/token_auth.md +++ b/docs/my-website/docs/proxy/token_auth.md @@ -790,6 +790,47 @@ litellm_jwtauth: user_roles_jwt_field: "resource_access.your-client.roles" ``` +## Route JWT-Shaped Machine Tokens to OAuth2 + +Use this when both are enabled: +- `enable_jwt_auth: true` for standard JWT validation +- `enable_oauth2_auth: true` for OAuth2 introspection + +If some machine tokens are also JWT-shaped, configure `routing_overrides` to route matching tokens to OAuth2. + +```yaml title="config.yaml" +general_settings: + enable_jwt_auth: true + enable_oauth2_auth: true + litellm_jwtauth: + user_id_jwt_field: "sub" + routing_overrides: + - iss: "machine-issuer.example.com" + client_id: "MID_LITELLM" + path: "oauth2" +``` + +### Matching behavior + +- A rule matches when all configured selectors match token claims +- Supported selectors: `iss` (required), `client_id` (optional), `aud` (optional) +- Selector values support both string and list forms +- If no rule matches, LiteLLM continues with standard JWT validation + +### List-based override example + +```yaml title="config.yaml" +general_settings: + enable_jwt_auth: true + enable_oauth2_auth: true + litellm_jwtauth: + routing_overrides: + - iss: ["machine-issuer.example.com", "backup-issuer.example.com"] + client_id: ["MID_LITELLM", "MID_BACKUP"] + aud: ["api://litellm", "api://fallback"] + path: "oauth2" +``` + ## [BETA] Control Access with OIDC Roles Allow JWT tokens with supported roles to access the proxy. diff --git a/litellm/litellm_core_utils/prompt_templates/common_utils.py b/litellm/litellm_core_utils/prompt_templates/common_utils.py index cec61405ebb..46e60c24d39 100644 --- a/litellm/litellm_core_utils/prompt_templates/common_utils.py +++ b/litellm/litellm_core_utils/prompt_templates/common_utils.py @@ -337,24 +337,35 @@ def _insert_assistant_continue_message( """ Add assistant continuation messages between consecutive user messages. - Only checks directly adjacent messages to preserve backward compatibility. + Skips tool messages and assistant messages with tool calls in the + alternation check, matching strict templates like llama.cpp. """ if not ensure_alternating_roles or len(messages) <= 1: return messages continue_message = assistant_continue_message or DEFAULT_ASSISTANT_CONTINUE_MESSAGE + # Find indexes where assistant_continue should be inserted (before that index) + insert_before_indexes: set = set() + + for i in range(len(messages)): + curr = messages[i] + if _counts_for_alternation(curr) and curr["role"] == "user": + # Look backwards for the previous counted message + j = i - 1 + while j >= 0: + if _counts_for_alternation(messages[j]): + if messages[j]["role"] == "user": + insert_before_indexes.add(i) + break + j -= 1 + + # Build the result with assistant_continue inserted at the right positions modified_messages: List[AllMessageValues] = [] for i, message in enumerate(messages): - if ( - i < len(messages) - 1 - and message.get("role") == "user" - and messages[i + 1].get("role") == "user" - ): - modified_messages.append(message) + if i in insert_before_indexes: modified_messages.append(continue_message) - else: - modified_messages.append(message) + modified_messages.append(message) return modified_messages diff --git a/litellm/llms/bedrock/chat/agentcore/transformation.py b/litellm/llms/bedrock/chat/agentcore/transformation.py index d6eb5a734c4..f066322b814 100644 --- a/litellm/llms/bedrock/chat/agentcore/transformation.py +++ b/litellm/llms/bedrock/chat/agentcore/transformation.py @@ -19,6 +19,7 @@ from litellm.litellm_core_utils.prompt_templates.common_utils import ( from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMException from litellm.llms.bedrock.base_aws_llm import BaseAWSLLM +from litellm.llms.a2a.common_utils import extract_text_from_a2a_response from litellm.llms.bedrock.common_utils import BedrockError from litellm.types.llms.bedrock_agentcore import ( AgentCoreMessage, @@ -343,6 +344,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): Parse direct JSON response (non-streaming). Supports multiple agent response schemas: + 0. {"jsonrpc": "2.0", "result": {"message": {"parts": [...]}}} - A2A JSON-RPC 1. {"result": {"role": "assistant", "content": [{"text": "..."}]}} - standard AgentCore 2. {"response": [{"text": "..."}]} - Strands agent format 3. {"result": "plain text"} or {"response": "plain text"} - simple string @@ -361,6 +363,18 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM): final_message=None, ) + # Strategy 0: A2A JSON-RPC format + # {"jsonrpc": "2.0", "result": {"message": {"parts": [{"kind": "text", "text": "..."}]}}} + if "jsonrpc" in response_json: + content = extract_text_from_a2a_response(response_json) + if content: + return AgentCoreParsedResponse( + content=content, + usage=None, + final_message=None, + ) + # Fall through to other strategies if A2A extraction returned empty + # Strategy 1: {"result": {"content": [{"text": "..."}]}} - standard AgentCore format if "result" in response_json and isinstance(response_json["result"], dict): result = response_json["result"] diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 8faf36df4c6..e4702364a3e 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -4098,6 +4098,24 @@ class ScopeMapping(OIDCPermissions): } +class JWTRoutingOverride(BaseModel): + """ + Override default auth routing for JWT-shaped bearer tokens. + + A rule matches when all provided selectors match token claims. + If matched, request is routed to the configured auth path. + """ + + iss: Union[str, List[str]] + client_id: Optional[Union[str, List[str]]] = None + aud: Optional[Union[str, List[str]]] = None + path: Literal["oauth2"] = "oauth2" + + model_config = { + "extra": "forbid", + } + + class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase): """ A class to define the roles and permissions for a LiteLLM Proxy w/ JWT Auth. @@ -4198,6 +4216,10 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase): default=300, description="TTL (seconds) for caching JWT-to-virtual-key mapping lookups.", ) + routing_overrides: Optional[List[JWTRoutingOverride]] = Field( + default=None, + description="Optional claim-based routing overrides for JWT-shaped tokens. Matching rules route requests to oauth2 before default JWT flow.", + ) ######################################################### def __init__(self, **kwargs: Any) -> None: diff --git a/litellm/proxy/auth/handle_jwt.py b/litellm/proxy/auth/handle_jwt.py index 6ad372f3b5a..4a6856b6d14 100644 --- a/litellm/proxy/auth/handle_jwt.py +++ b/litellm/proxy/auth/handle_jwt.py @@ -16,6 +16,8 @@ from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from fastapi import HTTPException +import jwt +from jwt.api_jwk import PyJWK from litellm._logging import verbose_proxy_logger from litellm.caching.caching import DualCache @@ -71,6 +73,21 @@ class JWTHandler: prisma_client: Optional[PrismaClient] user_api_key_cache: DualCache + # Supported algos: https://pyjwt.readthedocs.io/en/stable/algorithms.html + # "Warning: Make sure not to mix symmetric and asymmetric algorithms that interpret + # the key in different ways (e.g. HS* and RS*)." + SUPPORTED_JWT_ALGORITHMS = [ + "RS256", + "RS384", + "RS512", + "PS256", + "PS384", + "PS512", + "ES256", + "ES384", + "ES512", + "EdDSA", + ] def __init__( self, @@ -97,6 +114,30 @@ class JWTHandler: parts = token.split(".") return len(parts) == 3 + @staticmethod + def get_unverified_claims(token: str) -> Optional[dict]: + """ + Decode JWT claims without signature verification. + Used for routing decisions before selecting validation path. + """ + if not JWTHandler.is_jwt(token): + return None + + try: + claims = jwt.decode( + token, + options={"verify_signature": False, "verify_aud": False}, + algorithms=JWTHandler.SUPPORTED_JWT_ALGORITHMS, + ) + if isinstance(claims, dict): + return claims + return None + except Exception as e: + verbose_proxy_logger.debug( + "Failed to decode unverified JWT claims for routing: %s", e + ) + return None + def _rbac_role_from_role_mapping(self, token: dict) -> Optional[RBAC_ROLES]: """ Returns the RBAC role the token 'belongs' to based on role mappings. @@ -664,30 +705,11 @@ class JWTHandler: raise Exception(f"Failed to fetch OIDC UserInfo: {str(e)}") async def auth_jwt(self, token: str) -> dict: - # Supported algos: https://pyjwt.readthedocs.io/en/stable/algorithms.html - # "Warning: Make sure not to mix symmetric and asymmetric algorithms that interpret - # the key in different ways (e.g. HS* and RS*)." - algorithms = [ - "RS256", - "RS384", - "RS512", - "PS256", - "PS384", - "PS512", - "ES256", - "ES384", - "ES512", - "EdDSA", - ] - audience = os.getenv("JWT_AUDIENCE") decode_options = None if audience is None: decode_options = {"verify_aud": False} - import jwt - from jwt.api_jwk import PyJWK - header = jwt.get_unverified_header(token) verbose_proxy_logger.debug("header: %s", header) @@ -721,7 +743,7 @@ class JWTHandler: payload = jwt.decode( token, public_key_obj, # type: ignore - algorithms=algorithms, + algorithms=self.SUPPORTED_JWT_ALGORITHMS, options=decode_options, # type: ignore[arg-type] audience=audience, leeway=self.leeway, # allow testing of expired tokens @@ -749,7 +771,7 @@ class JWTHandler: payload = jwt.decode( token, key, - algorithms=algorithms, + algorithms=self.SUPPORTED_JWT_ALGORITHMS, audience=audience, options=decode_options, ) diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 53ae08aefb1..046c39a9101 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -11,7 +11,7 @@ import asyncio import re import secrets from datetime import datetime, timezone -from typing import List, Optional, Tuple, cast +from typing import Any, List, Optional, Tuple, cast import fastapi from fastapi import HTTPException, Request, WebSocket, status @@ -139,6 +139,58 @@ def _get_bearer_token_or_received_api_key(api_key: str) -> str: return api_key +def _routing_selector_matches_claim( + selector_value: Optional[Any], claim_value: Optional[Any] +) -> bool: + if selector_value is None: + return True + + selector_list = ( + [str(v) for v in selector_value] + if isinstance(selector_value, list) + else [str(selector_value)] + ) + + if isinstance(claim_value, list): + claim_list = [str(v) for v in claim_value] + return any(v in claim_list for v in selector_list) + + return str(claim_value) in selector_list if claim_value is not None else False + + +def _matches_routing_override( + token_claims: dict, override: "JWTRoutingOverride" +) -> bool: + return ( + _routing_selector_matches_claim(override.iss, token_claims.get("iss")) + and _routing_selector_matches_claim( + override.client_id, token_claims.get("client_id") + ) + and _routing_selector_matches_claim(override.aud, token_claims.get("aud")) + ) + + +def _should_route_jwt_to_oauth2_override(token: str, jwt_handler: JWTHandler) -> bool: + routing_overrides = jwt_handler.litellm_jwtauth.routing_overrides + if not routing_overrides: + return False + + token_claims = jwt_handler.get_unverified_claims(token=token) + if token_claims is None: + return False + + for override in routing_overrides: + if override.path == "oauth2" and _matches_routing_override( + token_claims=token_claims, override=override + ): + verbose_proxy_logger.debug( + "JWT routing override matched. Routing token to OAuth2 introspection." + ) + return True + + return False + + def _get_bearer_token( api_key: str, ): @@ -649,12 +701,20 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 # - JWT tokens (3 dot-separated parts) -> skip OAuth2, fall through to JWT handler # - Opaque tokens -> use OAuth2 handler # This allows JWT for users and OAuth2 for M2M on the same instance - is_jwt_token = ( + is_jwt = ( jwt_handler.is_jwt(token=api_key) if general_settings.get("enable_jwt_auth", False) is True else False ) - if not is_jwt_token: + # Routing uses unverified JWT claims only to choose auth path. + # Final authentication is enforced by the selected validator. + route_jwt_to_oauth2 = ( + is_jwt + and _should_route_jwt_to_oauth2_override( + token=api_key, jwt_handler=jwt_handler + ) + ) + if not is_jwt or route_jwt_to_oauth2: # return UserAPIKeyAuth object # helper to check if the api_key is a valid oauth2 token from litellm.proxy.proxy_server import premium_user @@ -688,7 +748,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 jwt_claims: Optional[dict] if ( jwt_handler.litellm_jwtauth.oidc_userinfo_enabled - and not jwt_handler.is_jwt(token=api_key) + and not is_jwt ): jwt_claims = await jwt_handler.get_oidc_userinfo(token=api_key) else: @@ -1193,49 +1253,13 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 raise Exception( "Key is blocked. Update via `/key/unblock` if you're an admin." ) - config = valid_token.config - - if config != {}: - model_list = config.get("model_list", []) - new_model_list = model_list - verbose_proxy_logger.debug( - f"\n new llm router model list {new_model_list}" - ) - elif ( - isinstance(valid_token.models, list) - and "all-team-models" in valid_token.models - ): - # Do not do any validation at this step - # the validation will occur when checking the team has access to this model - pass - else: - model = get_model_from_request(request_data, route) - fallback_models = cast( - Optional[List[ALL_FALLBACK_MODEL_VALUES]], - request_data.get("fallbacks", None), - ) - - if model is not None: - await can_key_call_model( - model=model, - llm_model_list=llm_model_list, - valid_token=valid_token, - llm_router=llm_router, - ) - - if fallback_models is not None: - for m in fallback_models: - await can_key_call_model( - model=m["model"] if isinstance(m, dict) else m, - llm_model_list=llm_model_list, - valid_token=valid_token, - llm_router=llm_router, - ) - await is_valid_fallback_model( - model=m["model"] if isinstance(m, dict) else m, - llm_router=llm_router, - user_model=None, - ) + await _enforce_key_and_fallback_model_access( + valid_token=valid_token, + request_data=request_data, + route=route, + llm_model_list=llm_model_list, + llm_router=llm_router, + ) # Check 2. If user_id for this token is in budget - done in common_checks() if valid_token.user_id is not None: @@ -1764,6 +1788,61 @@ async def _lookup_end_user_and_apply_budget( return valid_token, end_user_object +async def _enforce_key_and_fallback_model_access( + *, + valid_token: UserAPIKeyAuth, + request_data: dict, + route: str, + llm_model_list: Optional[list], + llm_router: Optional[Any], +) -> None: + """ + Key-level model allowlist and client fallbacks (same as standard auth). + Not included in common_checks — common_checks enforces team/user/project model access only. + """ + config = valid_token.config + + if config != {}: + model_list = config.get("model_list", []) + new_model_list = model_list + verbose_proxy_logger.debug( + f"\n new llm router model list {new_model_list}" + ) + elif ( + isinstance(valid_token.models, list) + and "all-team-models" in valid_token.models + ): + pass + else: + model = get_model_from_request(request_data, route) + fallback_models = cast( + Optional[List[ALL_FALLBACK_MODEL_VALUES]], + request_data.get("fallbacks", None), + ) + + if model is not None: + await can_key_call_model( + model=model, + llm_model_list=llm_model_list, + valid_token=valid_token, + llm_router=llm_router, + ) + + if fallback_models is not None: + for m in fallback_models: + await can_key_call_model( + model=m["model"] if isinstance(m, dict) else m, + llm_model_list=llm_model_list, + valid_token=valid_token, + llm_router=llm_router, + ) + await is_valid_fallback_model( + model=m["model"] if isinstance(m, dict) else m, + llm_router=llm_router, + user_model=None, + ) + + async def _run_post_custom_auth_checks( valid_token: UserAPIKeyAuth, request: Request, @@ -1773,6 +1852,7 @@ async def _run_post_custom_auth_checks( ) -> UserAPIKeyAuth: from litellm.proxy.proxy_server import ( general_settings, + llm_model_list, llm_router, model_max_budget_limiter, prisma_client, @@ -1816,6 +1896,15 @@ async def _run_post_custom_auth_checks( ), ) + if general_settings.get("custom_auth_run_common_checks", False): + await _enforce_key_and_fallback_model_access( + valid_token=valid_token, + request_data=request_data, + route=route, + llm_model_list=llm_model_list, + llm_router=llm_router, + ) + current_model = request_data.get("model", None) # 3. Check key-level model_max_budget diff --git a/tests/llm_translation/test_prompt_factory.py b/tests/llm_translation/test_prompt_factory.py index 64556c3f26d..27b0539aa4f 100644 --- a/tests/llm_translation/test_prompt_factory.py +++ b/tests/llm_translation/test_prompt_factory.py @@ -859,8 +859,8 @@ def test_ensure_alternating_roles_three_consecutive_assistants(): ] -def test_ensure_alternating_roles_does_not_split_tool_call_chain(): - """Tool-call chains [user, assistant(tc), tool, user] are preserved as-is.""" +def test_ensure_alternating_roles_inserts_assistant_continue_across_tool_chain(): + """[user, assistant(tc), tool, user] gets assistant_continue before the second user.""" messages = [ {"role": "user", "content": "Search for X"}, { @@ -899,15 +899,16 @@ def test_ensure_alternating_roles_does_not_split_tool_call_chain(): ], }, {"role": "tool", "tool_call_id": "c1", "content": "results"}, + {"role": "assistant", "content": "Please continue."}, {"role": "user", "content": "Thanks, now do Y"}, ] def test_ensure_alternating_roles_assistant_tool_call_then_assistant(): """ - Preserve old behavior for malformed adjacent assistant turns: - [assistant(tool_calls), assistant(no-tool-calls), user] should insert - user_continue between assistant messages. + Malformed [assistant(tc), assistant(no-tc), user]: + user_continue inserts break between adjacents, then assistant_continue + fills the counted-sequence gap. """ messages = [ { @@ -945,6 +946,7 @@ def test_ensure_alternating_roles_assistant_tool_call_then_assistant(): } ], }, + {"role": "assistant", "content": "Please continue."}, {"role": "user", "content": "Please continue."}, {"role": "assistant", "content": "Here's what I found."}, {"role": "user", "content": "Thanks"}, @@ -993,10 +995,184 @@ def test_ensure_alternating_roles_trailing_tool_call_assistant(): } ], }, + {"role": "assistant", "content": "Please continue."}, {"role": "user", "content": "Please continue."}, ] +def test_ensure_alternating_roles_multiple_tool_results(): + """[user, assistant(tc), tool, tool, user] — multiple tool results before next user.""" + messages = [ + {"role": "user", "content": "Search for X and Y"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c1", + "type": "function", + "function": {"name": "search_x", "arguments": "{}"}, + }, + { + "id": "c2", + "type": "function", + "function": {"name": "search_y", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c1", "content": "result X"}, + {"role": "tool", "tool_call_id": "c2", "content": "result Y"}, + {"role": "user", "content": "Thanks"}, + ] + + transformed_messages = get_completion_messages( + messages=messages, + assistant_continue_message=None, + user_continue_message=None, + ensure_alternating_roles=True, + ) + + assert transformed_messages == [ + {"role": "user", "content": "Search for X and Y"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c1", + "type": "function", + "function": {"name": "search_x", "arguments": "{}"}, + }, + { + "id": "c2", + "type": "function", + "function": {"name": "search_y", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c1", "content": "result X"}, + {"role": "tool", "tool_call_id": "c2", "content": "result Y"}, + {"role": "assistant", "content": "Please continue."}, + {"role": "user", "content": "Thanks"}, + ] + + +def test_ensure_alternating_roles_chained_tool_calls(): + """[user, assistant(tc), tool, assistant(tc), tool, user] — chained tool calls.""" + messages = [ + {"role": "user", "content": "Do multi-step task"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c1", + "type": "function", + "function": {"name": "step1", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c1", "content": "step1 done"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c2", + "type": "function", + "function": {"name": "step2", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c2", "content": "step2 done"}, + {"role": "user", "content": "What happened?"}, + ] + + transformed_messages = get_completion_messages( + messages=messages, + assistant_continue_message=None, + user_continue_message=None, + ensure_alternating_roles=True, + ) + + assert transformed_messages == [ + {"role": "user", "content": "Do multi-step task"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c1", + "type": "function", + "function": {"name": "step1", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c1", "content": "step1 done"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c2", + "type": "function", + "function": {"name": "step2", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c2", "content": "step2 done"}, + {"role": "assistant", "content": "Please continue."}, + {"role": "user", "content": "What happened?"}, + ] + + +def test_ensure_alternating_roles_system_prefix_with_tool_chain(): + """[system, user, assistant(tc), tool, user] — system prefix doesn't interfere.""" + messages = [ + {"role": "system", "content": "You are helpful."}, + {"role": "user", "content": "Search for X"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c1", + "type": "function", + "function": {"name": "search", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c1", "content": "results"}, + {"role": "user", "content": "Thanks"}, + ] + + transformed_messages = get_completion_messages( + messages=messages, + assistant_continue_message=None, + user_continue_message=None, + ensure_alternating_roles=True, + ) + + assert transformed_messages == [ + {"role": "system", "content": "You are helpful."}, + {"role": "user", "content": "Search for X"}, + { + "role": "assistant", + "content": None, + "tool_calls": [ + { + "id": "c1", + "type": "function", + "function": {"name": "search", "arguments": "{}"}, + }, + ], + }, + {"role": "tool", "tool_call_id": "c1", "content": "results"}, + {"role": "assistant", "content": "Please continue."}, + {"role": "user", "content": "Thanks"}, + ] + + def test_alternating_roles_e2e(): from litellm.llms.custom_httpx.http_handler import HTTPHandler import json diff --git a/tests/test_litellm/llms/bedrock/chat/agentcore/test_agentcore_transformation.py b/tests/test_litellm/llms/bedrock/chat/agentcore/test_agentcore_transformation.py index 3dede83032a..43182926f95 100644 --- a/tests/test_litellm/llms/bedrock/chat/agentcore/test_agentcore_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/agentcore/test_agentcore_transformation.py @@ -160,6 +160,67 @@ class TestAgentCoreJsonResponseParsing: assert parsed["content"] == "" assert parsed["final_message"] == response_json["result"] + def test_parse_json_a2a_jsonrpc_nested_message(self, config): + """Strategy 0: A2A JSON-RPC with result.message.parts[] format.""" + response_json = { + "jsonrpc": "2.0", + "id": "test_id", + "result": { + "message": { + "role": "agent", + "parts": [{"kind": "text", "text": "1 + 1 = 2"}], + "messageId": "123", + } + }, + } + parsed = config._parse_json_response(response_json) + assert parsed["content"] == "1 + 1 = 2" + assert parsed["usage"] is None + + def test_parse_json_a2a_jsonrpc_direct_parts(self, config): + """Strategy 0: A2A JSON-RPC with result.parts[] format (direct message).""" + response_json = { + "jsonrpc": "2.0", + "id": "test_id", + "result": { + "kind": "message", + "parts": [{"kind": "text", "text": "Direct response"}], + }, + } + parsed = config._parse_json_response(response_json) + assert parsed["content"] == "Direct response" + assert parsed["usage"] is None + + def test_parse_json_a2a_jsonrpc_multi_parts(self, config): + """Strategy 0: A2A JSON-RPC with multiple text parts concatenated.""" + response_json = { + "jsonrpc": "2.0", + "id": "test_id", + "result": { + "message": { + "role": "agent", + "parts": [ + {"kind": "text", "text": "First part"}, + {"kind": "text", "text": "Second part"}, + ], + } + }, + } + parsed = config._parse_json_response(response_json) + assert parsed["content"] == "First part Second part" + assert parsed["usage"] is None + + def test_parse_json_a2a_jsonrpc_empty_falls_through(self, config): + """Strategy 0: A2A JSON-RPC with empty result falls through to Strategy 3.""" + response_json = { + "jsonrpc": "2.0", + "id": "test_id", + "result": "plain text fallback", + } + parsed = config._parse_json_response(response_json) + assert parsed["content"] == "plain text fallback" + assert parsed["usage"] is None + class TestAgentCoreNonStreamingJsonFormats: """Tests for _get_parsed_response with different JSON formats (non-streaming path).""" diff --git a/tests/test_litellm/proxy/auth/test_user_api_key_auth.py b/tests/test_litellm/proxy/auth/test_user_api_key_auth.py index 74c7f9bca5f..6e1b245b3de 100644 --- a/tests/test_litellm/proxy/auth/test_user_api_key_auth.py +++ b/tests/test_litellm/proxy/auth/test_user_api_key_auth.py @@ -3,22 +3,30 @@ import json import os import sys from typing import Tuple -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import ANY, AsyncMock, MagicMock, patch sys.path.insert( 0, os.path.abspath("../../..") ) # Adds the parent directory to the system path -from unittest.mock import MagicMock - import pytest import litellm.proxy.proxy_server from litellm.caching.dual_cache import DualCache -from litellm.proxy._types import LiteLLM_JWTAuth, UserAPIKeyAuth +from litellm.proxy._types import ( + LiteLLM_JWTAuth, + ProxyErrorTypes, + ProxyException, + UserAPIKeyAuth, + JWTRoutingOverride, +) from litellm.proxy.auth.handle_jwt import JWTHandler from litellm.proxy.auth.route_checks import RouteChecks -from litellm.proxy.auth.user_api_key_auth import get_api_key, user_api_key_auth +from litellm.proxy.auth.user_api_key_auth import ( + _run_post_custom_auth_checks, + get_api_key, + user_api_key_auth, +) def test_get_api_key(): @@ -38,6 +46,86 @@ def test_get_api_key(): ) == (api_key, passed_in_key) +@pytest.mark.asyncio +async def test_custom_auth_does_not_enforce_key_model_access_by_default(): + valid_token = UserAPIKeyAuth(token="test_token", models=["gpt-4o-mini"]) + request_data = {"model": "gpt-4o"} + + with patch( + "litellm.proxy.auth.user_api_key_auth.can_key_call_model", new_callable=AsyncMock + ) as mock_can_key, patch( + "litellm.proxy.proxy_server.general_settings", + {}, + ): + await _run_post_custom_auth_checks( + valid_token=valid_token, + request=None, + request_data=request_data, + route="/v1/chat/completions", + parent_otel_span=None, + ) + mock_can_key.assert_not_awaited() + + +@pytest.mark.asyncio +async def test_custom_auth_honors_key_level_model_access_restriction_allowed_with_opt_in(): + valid_token = UserAPIKeyAuth(token="test_token", models=["gpt-4o-mini"]) + request_data = {"model": "gpt-4o-mini"} + + with patch( + "litellm.proxy.auth.user_api_key_auth.can_key_call_model", new_callable=AsyncMock + ) as mock_can_key, patch( + "litellm.proxy.auth.user_api_key_auth.common_checks", new_callable=AsyncMock + ), patch( + "litellm.proxy.proxy_server.general_settings", + {"custom_auth_run_common_checks": True}, + ): + await _run_post_custom_auth_checks( + valid_token=valid_token, + request=None, + request_data=request_data, + route="/v1/chat/completions", + parent_otel_span=None, + ) + mock_can_key.assert_awaited_once_with( + model="gpt-4o-mini", + llm_model_list=ANY, + valid_token=valid_token, + llm_router=ANY, + ) + + +@pytest.mark.asyncio +async def test_custom_auth_honors_key_level_model_access_restriction_denied_with_opt_in(): + valid_token = UserAPIKeyAuth(token="test_token", models=["gpt-4o-mini"]) + request_data = {"model": "gpt-4o"} + + with patch( + "litellm.proxy.auth.user_api_key_auth.can_key_call_model", new_callable=AsyncMock + ) as mock_can_key, patch( + "litellm.proxy.auth.user_api_key_auth.common_checks", new_callable=AsyncMock + ), patch( + "litellm.proxy.proxy_server.general_settings", + {"custom_auth_run_common_checks": True}, + ): + mock_can_key.side_effect = ProxyException( + message="Key not allowed to access model", + type=ProxyErrorTypes.key_model_access_denied, + param="model", + code=401, + ) + with pytest.raises(ProxyException) as exc: + await _run_post_custom_auth_checks( + valid_token=valid_token, + request=None, + request_data=request_data, + route="/v1/chat/completions", + parent_otel_span=None, + ) + + assert exc.value.type == ProxyErrorTypes.key_model_access_denied + + @pytest.mark.parametrize( "custom_litellm_key_header, api_key, passed_in_key", [ @@ -689,6 +777,203 @@ class TestJWTOAuth2Coexistence: mock_jwt_auth.assert_called_once() assert result.user_id == "jwt-human-user" + @pytest.mark.asyncio + async def test_routing_override_routes_matching_jwt_to_oauth2(self): + """ + When routing_overrides match JWT claims, route JWT-shaped token to OAuth2. + """ + jwt_token = ( + "eyJhbGciOiJSUzI1NiJ9." + "eyJpc3MiOiJtYWNoaW5lLWlzc3Vlci5leGFtcGxlLmNvbSIsImNsaWVudF9pZCI6Ik1JRF9MSVRFTExNIn0." + "c2ln" + ) + general_settings = { + "enable_oauth2_auth": True, + "enable_jwt_auth": True, + } + mock_oauth2_response = UserAPIKeyAuth( + api_key=jwt_token, + user_id="machine-client-override", + ) + + mock_request = MagicMock() + mock_request.url.path = "/v1/chat/completions" + mock_request.headers = {"authorization": f"Bearer {jwt_token}"} + mock_request.query_params = {} + + with patch( + "litellm.proxy.proxy_server.general_settings", general_settings + ), patch("litellm.proxy.proxy_server.premium_user", True), patch( + "litellm.proxy.proxy_server.master_key", "sk-master" + ), patch( + "litellm.proxy.proxy_server.prisma_client", None + ), patch( + "litellm.proxy.auth.user_api_key_auth.Oauth2Handler.check_oauth2_token", + new_callable=AsyncMock, + return_value=mock_oauth2_response, + ) as mock_oauth2, patch( + "litellm.proxy.auth.user_api_key_auth.JWTAuthManager.auth_builder", + new_callable=AsyncMock, + ) as mock_jwt_auth: + litellm.proxy.proxy_server.jwt_handler.update_environment( + prisma_client=None, + user_api_key_cache=DualCache(), + litellm_jwtauth=LiteLLM_JWTAuth( + routing_overrides=[ + JWTRoutingOverride( + iss="machine-issuer.example.com", + client_id="MID_LITELLM", + path="oauth2", + ) + ] + ), + ) + + result = await user_api_key_auth( + request=mock_request, + api_key=f"Bearer {jwt_token}", + ) + + mock_oauth2.assert_called_once_with(token=jwt_token) + mock_jwt_auth.assert_not_called() + assert result.user_id == "machine-client-override" + + @pytest.mark.asyncio + async def test_routing_override_does_not_match_client_id_falls_back_to_jwt(self): + """ + If override ISS matches but client_id does not, continue default JWT flow. + """ + jwt_token = ( + "eyJhbGciOiJSUzI1NiJ9." + "eyJpc3MiOiJtYWNoaW5lLWlzc3Vlci5leGFtcGxlLmNvbSIsImNsaWVudF9pZCI6IlVTRVJfUE9SVEFMIn0." + "c2ln" + ) + general_settings = { + "enable_oauth2_auth": True, + "enable_jwt_auth": True, + } + mock_jwt_result = { + "is_proxy_admin": True, + "team_object": None, + "user_object": None, + "end_user_object": None, + "org_object": None, + "token": jwt_token, + "team_id": "jwt-team", + "user_id": "jwt-user-no-override", + "end_user_id": None, + "org_id": None, + "team_membership": None, + "jwt_claims": {"sub": "user1"}, + } + + mock_request = MagicMock() + mock_request.url.path = "/v1/chat/completions" + mock_request.headers = {"authorization": f"Bearer {jwt_token}"} + mock_request.query_params = {} + + with patch( + "litellm.proxy.proxy_server.general_settings", general_settings + ), patch("litellm.proxy.proxy_server.premium_user", True), patch( + "litellm.proxy.proxy_server.master_key", "sk-master" + ), patch( + "litellm.proxy.proxy_server.prisma_client", None + ), patch( + "litellm.proxy.auth.user_api_key_auth.Oauth2Handler.check_oauth2_token", + new_callable=AsyncMock, + ) as mock_oauth2, patch( + "litellm.proxy.auth.user_api_key_auth.JWTAuthManager.auth_builder", + new_callable=AsyncMock, + return_value=mock_jwt_result, + ) as mock_jwt_auth: + litellm.proxy.proxy_server.jwt_handler.update_environment( + prisma_client=None, + user_api_key_cache=DualCache(), + litellm_jwtauth=LiteLLM_JWTAuth( + routing_overrides=[ + JWTRoutingOverride( + iss="machine-issuer.example.com", + client_id="MID_LITELLM", + path="oauth2", + ) + ] + ), + ) + + result = await user_api_key_auth( + request=mock_request, + api_key=f"Bearer {jwt_token}", + ) + + mock_oauth2.assert_not_called() + mock_jwt_auth.assert_called_once() + assert result.user_id == "jwt-user-no-override" + + @pytest.mark.asyncio + async def test_routing_override_matches_aud_claim_list_and_list_selectors(self): + """ + Match routing override when selectors are lists and token aud claim is a list. + """ + jwt_token = ( + "eyJhbGciOiJSUzI1NiJ9." + "eyJpc3MiOiJtYWNoaW5lLWlzc3Vlci5leGFtcGxlLmNvbSIsImNsaWVudF9pZCI6Ik1JRF9MSVRFTExNIiwiYXVkIjpbImFwaTovL2xpdGVsbG0iLCJhcGk6Ly9vdGhlciJdfQ." + "c2ln" + ) + general_settings = { + "enable_oauth2_auth": True, + "enable_jwt_auth": True, + } + mock_oauth2_response = UserAPIKeyAuth( + api_key=jwt_token, + user_id="machine-client-aud-list", + ) + + mock_request = MagicMock() + mock_request.url.path = "/v1/chat/completions" + mock_request.headers = {"authorization": f"Bearer {jwt_token}"} + mock_request.query_params = {} + + with patch( + "litellm.proxy.proxy_server.general_settings", general_settings + ), patch("litellm.proxy.proxy_server.premium_user", True), patch( + "litellm.proxy.proxy_server.master_key", "sk-master" + ), patch( + "litellm.proxy.proxy_server.prisma_client", None + ), patch( + "litellm.proxy.auth.user_api_key_auth.Oauth2Handler.check_oauth2_token", + new_callable=AsyncMock, + return_value=mock_oauth2_response, + ) as mock_oauth2, patch( + "litellm.proxy.auth.user_api_key_auth.JWTAuthManager.auth_builder", + new_callable=AsyncMock, + ) as mock_jwt_auth: + litellm.proxy.proxy_server.jwt_handler.update_environment( + prisma_client=None, + user_api_key_cache=DualCache(), + litellm_jwtauth=LiteLLM_JWTAuth( + routing_overrides=[ + JWTRoutingOverride( + iss=[ + "machine-issuer.example.com", + "other-issuer.example.com", + ], + client_id=["MID_LITELLM", "MID_BACKUP"], + aud=["api://litellm", "api://fallback"], + path="oauth2", + ) + ] + ), + ) + + result = await user_api_key_auth( + request=mock_request, + api_key=f"Bearer {jwt_token}", + ) + + mock_oauth2.assert_called_once_with(token=jwt_token) + mock_jwt_auth.assert_not_called() + assert result.user_id == "machine-client-aud-list" + @pytest.mark.asyncio async def test_only_oauth2_enabled_handles_all_tokens(self): """ From fa629c307c31d7b9793b9b2137a67ca71190ce8a Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 2 Apr 2026 17:29:47 -0700 Subject: [PATCH 25/32] [Fix] Dockerfile.non_root: install node-gyp for npm ci The wolfi-base npm@11.12.1 package does not bundle node-gyp, causing `npm ci` to fail with `Cannot find module 'node-gyp/bin/node-gyp.js'` when building the Admin UI in the non-root Docker image. Install node-gyp@12.2.0 globally and symlink it into npm's internal node_modules where @npmcli/run-script expects to find it. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/Dockerfile.non_root | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index 1cf6c0dfd15..bf1af9ed756 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -46,7 +46,10 @@ ENV LITELLM_NON_ROOT=true # package-lock.json with pinned versions + integrity hashes. RUN mkdir -p /var/lib/litellm/ui && \ mv /app/.npmrc /app/.npmrc.bak && \ - npm install -g npm@11.12.1 && npm cache clean --force && \ + npm install -g npm@11.12.1 && \ + npm install -g node-gyp@12.2.0 && \ + ln -sf /usr/local/lib/node_modules/node-gyp /usr/lib/node_modules/npm/node_modules/node-gyp && \ + npm cache clean --force && \ cd /app/ui/litellm-dashboard && \ if [ -f "/app/enterprise/enterprise_ui/enterprise_colors.json" ]; then \ cp /app/enterprise/enterprise_ui/enterprise_colors.json ./ui_colors.json; \ From d4813a2a0f01c0bc4f48959d8d90d3e54d66ffa9 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 2 Apr 2026 17:31:16 -0700 Subject: [PATCH 26/32] adding poetry lock --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4798b6122d5..dff1b8781d5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3598,15 +3598,15 @@ files = [ [[package]] name = "litellm-proxy-extras" -version = "0.4.62" +version = "0.4.63" description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package." optional = true python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" groups = ["main"] markers = "extra == \"proxy\"" files = [ - {file = "litellm_proxy_extras-0.4.62-py3-none-any.whl", hash = "sha256:cf91c1a83d94000b8997ee29d9e8d505d1ad80c26f111803bef5365174c97de0"}, - {file = "litellm_proxy_extras-0.4.62.tar.gz", hash = "sha256:0d87db1cda9851717e5294f2fa2c7ae1f34d7476d99e24e6462702e11a2cdd88"}, + {file = "litellm_proxy_extras-0.4.63-py3-none-any.whl", hash = "sha256:46ec50083832b6b5ead86e53003657e1a53dc27bd95cbdbaee9c1343726e3acb"}, + {file = "litellm_proxy_extras-0.4.63.tar.gz", hash = "sha256:7161b27c3b38a840c13bb113b733196efafe2bb4d2ba22c9bd6e359c4b753aa2"}, ] [[package]] @@ -8309,4 +8309,4 @@ utils = ["numpydoc"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "f507b7c5060793a3325171c5245376057fc0f61a3a9443e9acd88d23a939a14a" +content-hash = "9a2476d5f234f3ce45f399a77fb9e86bd0025e27e2bb905b0ecac7848c4a758c" From ee3e848deddd275cca1ad0a0abb20b01ab8b1135 Mon Sep 17 00:00:00 2001 From: Joe Reyna Date: Thu, 2 Apr 2026 21:13:33 -0700 Subject: [PATCH 27/32] allow hashed token_id in /key/update endpoint (#24969) --- .../management_endpoints/key_management_endpoints.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index c140de98191..e105d9b8586 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -942,9 +942,9 @@ async def _check_team_key_limits( where={"team_id": team_table.team_id}, ) # Exclude the key being updated to avoid double-counting its limits. - # key.token is the SHA-256 hash stored in DB; data.key is the raw key string. + # data.key may be a raw key (sk-...) or a pre-hashed token_id. if isinstance(data, UpdateKeyRequest): - hashed_key = hash_token(data.key) + hashed_key = _hash_token_if_needed(data.key) keys = [key for key in keys if key.token != hashed_key] check_team_key_model_specific_limits( keys=keys, @@ -1101,9 +1101,9 @@ async def _check_org_key_limits( where={"organization_id": org_table.organization_id}, ) # Exclude the key being updated to avoid double-counting its limits. - # key.token is the SHA-256 hash stored in DB; data.key is the raw key string. + # data.key may be a raw key (sk-...) or a pre-hashed token_id. if isinstance(data, UpdateKeyRequest): - hashed_key = hash_token(data.key) + hashed_key = _hash_token_if_needed(data.key) keys = [key for key in keys if key.token != hashed_key] check_org_key_model_specific_limits( keys=keys, @@ -2157,7 +2157,7 @@ async def update_key_fn( # Delete - key from cache, since it's been updated! # key updated - a new model could have been added to this key. it should not block requests after this is done await _delete_cache_key_object( - hashed_token=hash_token(key), + hashed_token=_hash_token_if_needed(key), user_api_key_cache=user_api_key_cache, proxy_logging_obj=proxy_logging_obj, ) From 1e5b79d887ca01c3ac477db837e9d830697d12b4 Mon Sep 17 00:00:00 2001 From: ishaan-berri <155045088+ishaan-berri@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:13:56 -0700 Subject: [PATCH 28/32] =?UTF-8?q?[Bedrock]=20Fix=20Anthropic=20file=5Fid?= =?UTF-8?q?=20support=20-=20async=20path=20+=20document=20URL=E2=86=92base?= =?UTF-8?q?64=20+=20beta=20header=20filtering=20(#25047)=20(#25050)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ishaan Jaffer --- litellm/llms/bedrock/chat/invoke_handler.py | 115 +++++++++++ .../anthropic_claude3_transformation.py | 188 ++++++++++++++++-- .../anthropic_claude3_transformation.py | 13 +- 3 files changed, 291 insertions(+), 25 deletions(-) diff --git a/litellm/llms/bedrock/chat/invoke_handler.py b/litellm/llms/bedrock/chat/invoke_handler.py index 1077731779d..67bba28e4c5 100644 --- a/litellm/llms/bedrock/chat/invoke_handler.py +++ b/litellm/llms/bedrock/chat/invoke_handler.py @@ -855,6 +855,32 @@ class BedrockLLM(BaseAWSLLM): endpoint_url = f"{endpoint_url}/model/{modelId}/invoke" proxy_endpoint_url = f"{proxy_endpoint_url}/model/{modelId}/invoke" + if acompletion and provider == "anthropic" and self.is_claude_messages_api_model( + model + ): + if isinstance(client, HTTPHandler): + client = None + return self._async_anthropic_messages_completion( + model=model, + messages=messages, + endpoint_url=endpoint_url, + proxy_endpoint_url=proxy_endpoint_url, + credentials=credentials, + aws_region_name=aws_region_name, + model_response=model_response, + print_verbose=print_verbose, + encoding=encoding, + logging_obj=logging_obj, + optional_params=optional_params, + stream=stream, + litellm_params=litellm_params, + logger_fn=logger_fn, + extra_headers=extra_headers, + timeout=timeout, + client=client, + stream_chunk_size=stream_chunk_size, + ) # type: ignore[return-value] + prompt, chat_history = self.convert_messages_to_prompt( model, messages, provider, custom_prompt_dict ) @@ -1148,6 +1174,95 @@ class BedrockLLM(BaseAWSLLM): encoding=encoding, ) + async def _async_anthropic_messages_completion( + self, + model: str, + messages: list, + endpoint_url: str, + proxy_endpoint_url: str, + credentials, + aws_region_name: str, + model_response: ModelResponse, + print_verbose: Callable, + encoding, + logging_obj: Logging, + optional_params: dict, + stream, + litellm_params=None, + logger_fn=None, + extra_headers: Optional[dict] = None, + timeout: Optional[Union[float, httpx.Timeout]] = None, + client: Optional[AsyncHTTPHandler] = None, + stream_chunk_size: int = 1024, + ) -> Union[ModelResponse, CustomStreamWrapper]: + transformed_request = await litellm.AmazonAnthropicClaudeConfig().async_transform_request( + model=model, + messages=messages, + optional_params=optional_params, + litellm_params=litellm_params or {}, + headers=extra_headers or {}, + ) + data = json.dumps(transformed_request) + + headers = {"Content-Type": "application/json"} + if extra_headers is not None: + headers = {"Content-Type": "application/json", **extra_headers} + prepped = self.get_request_headers( + credentials=credentials, + aws_region_name=aws_region_name, + extra_headers=extra_headers, + endpoint_url=endpoint_url, + data=data, + headers=headers, + ) + + logging_obj.pre_call( + input=messages, + api_key="", + additional_args={ + "complete_input_dict": data, + "api_base": proxy_endpoint_url, + "headers": prepped.headers, + }, + ) + + if stream is True: + return await self.async_streaming( + model=model, + messages=messages, + data=data, + api_base=proxy_endpoint_url, + model_response=model_response, + print_verbose=print_verbose, + encoding=encoding, + logging_obj=logging_obj, + optional_params=optional_params, + stream=True, + litellm_params=litellm_params, + logger_fn=logger_fn, + headers=prepped.headers, + timeout=timeout, + client=client, + stream_chunk_size=stream_chunk_size, + ) + return await self.async_completion( + model=model, + messages=messages, + data=data, + api_base=proxy_endpoint_url, + model_response=model_response, + print_verbose=print_verbose, + encoding=encoding, + logging_obj=logging_obj, + optional_params=optional_params, + stream=stream, # type: ignore + litellm_params=litellm_params, + logger_fn=logger_fn, + headers=prepped.headers, + timeout=timeout, + client=client, + ) + async def async_completion( self, model: str, diff --git a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py index 7936b6ea644..2b28473ad3e 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py @@ -2,6 +2,14 @@ from typing import TYPE_CHECKING, Any, List, Optional import httpx +from litellm.anthropic_beta_headers_manager import filter_and_transform_beta_headers +from litellm.litellm_core_utils.prompt_templates.factory import ( + convert_to_anthropic_image_obj, +) +from litellm.litellm_core_utils.prompt_templates.image_handling import ( + async_convert_url_to_base64, + convert_url_to_base64, +) from litellm.llms.anthropic.chat.transformation import AnthropicConfig from litellm.llms.bedrock.chat.invoke_transformations.base_invoke_transformation import ( AmazonInvokeConfig, @@ -85,8 +93,62 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig): litellm_params: dict, headers: dict, ) -> dict: - # Filter out AWS authentication parameters before passing to Anthropic transformation - # AWS params should only be used for signing requests, not included in request body + _anthropic_request = self._build_bedrock_anthropic_request_base( + model=model, + messages=messages, + optional_params=optional_params, + litellm_params=litellm_params, + headers=headers, + ) + + self._convert_document_url_sources_to_base64(_anthropic_request) + beta_list = self._compute_bedrock_invoke_beta_headers( + model=model, + messages=messages, + optional_params=optional_params, + headers=headers, + ) + if beta_list: + _anthropic_request["anthropic_beta"] = beta_list + + return _anthropic_request + + async def async_transform_request( + self, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + litellm_params: dict, + headers: dict, + ) -> dict: + _anthropic_request = self._build_bedrock_anthropic_request_base( + model=model, + messages=messages, + optional_params=optional_params, + litellm_params=litellm_params, + headers=headers, + ) + + await self._async_convert_document_url_sources_to_base64(_anthropic_request) + beta_list = self._compute_bedrock_invoke_beta_headers( + model=model, + messages=messages, + optional_params=optional_params, + headers=headers, + ) + if beta_list: + _anthropic_request["anthropic_beta"] = beta_list + + return _anthropic_request + + def _build_bedrock_anthropic_request_base( + self, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + litellm_params: dict, + headers: dict, + ) -> dict: filtered_params = { k: v for k, v in optional_params.items() @@ -94,7 +156,7 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig): } filtered_params = self._normalize_bedrock_tool_search_tools(filtered_params) - _anthropic_request = AnthropicConfig.transform_request( + anthropic_request = AnthropicConfig.transform_request( self, model=model, messages=messages, @@ -103,28 +165,31 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig): headers=headers, ) - _anthropic_request.pop("model", None) - _anthropic_request.pop("stream", None) - # Bedrock Invoke doesn't support output_format parameter - _anthropic_request.pop("output_format", None) - # Bedrock Invoke doesn't support output_config parameter - # Fixes: https://github.com/BerriAI/litellm/issues/22797 - _anthropic_request.pop("output_config", None) - if "anthropic_version" not in _anthropic_request: - _anthropic_request["anthropic_version"] = self.anthropic_version + anthropic_request.pop("model", None) + anthropic_request.pop("stream", None) + anthropic_request.pop("output_format", None) + anthropic_request.pop("output_config", None) + if "anthropic_version" not in anthropic_request: + anthropic_request["anthropic_version"] = self.anthropic_version # Remove `custom` field from tools (Bedrock doesn't support it) - # Claude Code sends `custom: {defer_loading: true}` on tool definitions, - # which causes Bedrock to reject the request with "Extra inputs are not permitted" - # Ref: https://github.com/BerriAI/litellm/issues/22847 - remove_custom_field_from_tools(_anthropic_request) + remove_custom_field_from_tools(anthropic_request) + return anthropic_request + def _compute_bedrock_invoke_beta_headers( + self, + model: str, + messages: List[AllMessageValues], + optional_params: dict, + headers: dict, + ) -> List[str]: tools = optional_params.get("tools") tool_search_used = self.is_tool_search_used(tools) programmatic_tool_calling_used = self.is_programmatic_tool_calling_used(tools) input_examples_used = self.is_input_examples_used(tools) - beta_set = set(get_anthropic_beta_from_headers(headers)) + user_beta_set = set(get_anthropic_beta_from_headers(headers)) + beta_set = set(user_beta_set) auto_betas = self.get_anthropic_beta_list( model=model, optional_params=optional_params, @@ -142,12 +207,91 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig): if "opus-4" in model.lower() or "opus_4" in model.lower(): beta_set.add("tool-search-tool-2025-10-19") - # Filter out beta headers that Bedrock Invoke doesn't support - # Uses centralized configuration from anthropic_beta_headers_config.json - beta_list = list(beta_set) - _anthropic_request["anthropic_beta"] = beta_list + auto_beta_list = filter_and_transform_beta_headers( + beta_headers=list(beta_set - user_beta_set), + provider="bedrock", + ) + return sorted(user_beta_set.union(set(auto_beta_list))) - return _anthropic_request + def _convert_document_url_sources_to_base64(self, anthropic_request: dict) -> None: + """ + Bedrock Invoke does not accept document URL sources. Convert to base64 payloads. + """ + messages = anthropic_request.get("messages") + if not isinstance(messages, list): + return + + for message in messages: + if not isinstance(message, dict): + continue + content = message.get("content") + if not isinstance(content, list): + continue + + for block in content: + if not isinstance(block, dict) or block.get("type") != "document": + continue + source = block.get("source") + if not isinstance(source, dict) or source.get("type") != "url": + continue + source_url = source.get("url") + if not isinstance(source_url, str): + continue + + inferred_format: Optional[str] = None + if source_url.lower().endswith(".pdf"): + inferred_format = "application/pdf" + base64_url = convert_url_to_base64(url=source_url) + image_chunk = convert_to_anthropic_image_obj( + openai_image_url=base64_url, + format=inferred_format, + ) + block["source"] = { + "type": "base64", + "media_type": image_chunk["media_type"], + "data": image_chunk["data"], + } + + async def _async_convert_document_url_sources_to_base64( + self, anthropic_request: dict + ) -> None: + """ + Async version of document URL conversion for async completion paths. + """ + messages = anthropic_request.get("messages") + if not isinstance(messages, list): + return + + for message in messages: + if not isinstance(message, dict): + continue + content = message.get("content") + if not isinstance(content, list): + continue + + for block in content: + if not isinstance(block, dict) or block.get("type") != "document": + continue + source = block.get("source") + if not isinstance(source, dict) or source.get("type") != "url": + continue + source_url = source.get("url") + if not isinstance(source_url, str): + continue + + inferred_format: Optional[str] = None + if source_url.lower().endswith(".pdf"): + inferred_format = "application/pdf" + base64_url = await async_convert_url_to_base64(url=source_url) + image_chunk = convert_to_anthropic_image_obj( + openai_image_url=base64_url, + format=inferred_format, + ) + block["source"] = { + "type": "base64", + "media_type": image_chunk["media_type"], + "data": image_chunk["data"], + } def _normalize_bedrock_tool_search_tools(self, optional_params: dict) -> dict: """ diff --git a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py index a890cf2a04d..784c6a50cfd 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -12,6 +12,7 @@ from typing import ( import httpx +from litellm.anthropic_beta_headers_manager import filter_and_transform_beta_headers from litellm.llms.anthropic.common_utils import AnthropicModelInfo from litellm.llms.anthropic.experimental_pass_through.messages.transformation import ( AnthropicMessagesConfig, @@ -436,7 +437,8 @@ class AmazonAnthropicClaudeMessagesConfig( ) input_examples_used = anthropic_model_info.is_input_examples_used(tools) - beta_set = set(get_anthropic_beta_from_headers(headers)) + user_beta_set = set(get_anthropic_beta_from_headers(headers)) + beta_set = set(user_beta_set) auto_betas = anthropic_model_info.get_anthropic_beta_list( model=model, optional_params=anthropic_messages_optional_request_params, @@ -460,8 +462,13 @@ class AmazonAnthropicClaudeMessagesConfig( if "tool-search-tool-2025-10-19" in beta_set: beta_set.add("tool-examples-2025-10-29") - if beta_set: - anthropic_messages_request["anthropic_beta"] = list(beta_set) + filtered_auto_betas = filter_and_transform_beta_headers( + beta_headers=list(beta_set - user_beta_set), + provider="bedrock", + ) + filtered_betas = sorted(user_beta_set.union(set(filtered_auto_betas))) + if filtered_betas: + anthropic_messages_request["anthropic_beta"] = filtered_betas return anthropic_messages_request From 52a596d2a4402cef5990de848a6b354497a34eb0 Mon Sep 17 00:00:00 2001 From: Marty Sullivan Date: Fri, 3 Apr 2026 00:26:04 -0400 Subject: [PATCH 29/32] Bedrock Model Updates 2026-03-26 (#24645) * add new bedrock models & remove duplicate vertexai entry * adding non-regional entry for minimax-2.5 --- ...odel_prices_and_context_window_backup.json | 224 ++++++++++++++++++ model_prices_and_context_window.json | 224 ++++++++++++++++++ 2 files changed, 448 insertions(+) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 51b7b56a285..4072aab6544 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -6672,6 +6672,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-northeast-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/ap-northeast-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 7.3e-07, "litellm_provider": "bedrock", @@ -6781,6 +6795,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-south-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/ap-south-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 7.1e-07, "litellm_provider": "bedrock", @@ -6819,6 +6847,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-southeast-2/minimax.minimax-m2.5": { + "input_cost_per_token": 3.09e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.236e-06 + }, "bedrock/ap-southeast-3/deepseek.v3.2": { "input_cost_per_token": 7.4e-07, "litellm_provider": "bedrock", @@ -6845,6 +6887,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-southeast-3/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/ap-southeast-3/moonshotai.kimi-k2.5": { "input_cost_per_token": 7.2e-07, "litellm_provider": "bedrock", @@ -6916,6 +6972,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-north-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-north-1/moonshotai.kimi-k2.5": { "input_cost_per_token": 7.2e-07, "litellm_provider": "bedrock", @@ -7030,6 +7100,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-central-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-central-1/qwen.qwen3-coder-next": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7074,6 +7158,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-west-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-west-1/qwen.qwen3-coder-next": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7118,6 +7216,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-west-2/minimax.minimax-m2.5": { + "input_cost_per_token": 4.7e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.86e-06 + }, "bedrock/eu-west-2/qwen.qwen3-coder-next": { "input_cost_per_token": 7.8e-07, "litellm_provider": "bedrock", @@ -7174,6 +7286,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-south-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-south-1/qwen.qwen3-coder-next": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7249,6 +7375,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/sa-east-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/sa-east-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 7.3e-07, "litellm_provider": "bedrock", @@ -7449,6 +7589,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/us-east-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.2e-06 + }, "bedrock/us-east-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7513,6 +7667,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/us-east-2/minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.2e-06 + }, "bedrock/us-east-2/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7995,6 +8163,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/us-west-2/minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.2e-06 + }, "bedrock/us-west-2/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -21292,6 +21474,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "output_cost_per_token": 1.2e-06, + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "source": "https://aws.amazon.com/bedrock/pricing/" + }, "minimax/speech-02-hd": { "input_cost_per_character": 0.0001, "litellm_provider": "minimax", @@ -23111,6 +23307,20 @@ "source": "https://aws.amazon.com/bedrock/pricing/", "supports_native_structured_output": true }, + "nvidia.nemotron-super-3-120b": { + "input_cost_per_token": 1.5e-07, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 256000, + "max_output_tokens": 32768, + "max_tokens": 32768, + "mode": "chat", + "output_cost_per_token": 6.5e-07, + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true + }, "o1": { "cache_read_input_token_cost": 7.5e-06, "input_cost_per_token": 1.5e-05, @@ -32726,6 +32936,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "zai.glm-5": { + "input_cost_per_token": 1e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 200000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 3.2e-06, + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true + }, "zai/glm-5": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 2e-07, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 51b7b56a285..4072aab6544 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -6672,6 +6672,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-northeast-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/ap-northeast-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 7.3e-07, "litellm_provider": "bedrock", @@ -6781,6 +6795,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-south-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/ap-south-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 7.1e-07, "litellm_provider": "bedrock", @@ -6819,6 +6847,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-southeast-2/minimax.minimax-m2.5": { + "input_cost_per_token": 3.09e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.236e-06 + }, "bedrock/ap-southeast-3/deepseek.v3.2": { "input_cost_per_token": 7.4e-07, "litellm_provider": "bedrock", @@ -6845,6 +6887,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/ap-southeast-3/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/ap-southeast-3/moonshotai.kimi-k2.5": { "input_cost_per_token": 7.2e-07, "litellm_provider": "bedrock", @@ -6916,6 +6972,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-north-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-north-1/moonshotai.kimi-k2.5": { "input_cost_per_token": 7.2e-07, "litellm_provider": "bedrock", @@ -7030,6 +7100,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-central-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-central-1/qwen.qwen3-coder-next": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7074,6 +7158,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-west-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-west-1/qwen.qwen3-coder-next": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7118,6 +7216,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-west-2/minimax.minimax-m2.5": { + "input_cost_per_token": 4.7e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.86e-06 + }, "bedrock/eu-west-2/qwen.qwen3-coder-next": { "input_cost_per_token": 7.8e-07, "litellm_provider": "bedrock", @@ -7174,6 +7286,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/eu-south-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/eu-south-1/qwen.qwen3-coder-next": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7249,6 +7375,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/sa-east-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3.6e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.44e-06 + }, "bedrock/sa-east-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 7.3e-07, "litellm_provider": "bedrock", @@ -7449,6 +7589,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/us-east-1/minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.2e-06 + }, "bedrock/us-east-1/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7513,6 +7667,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/us-east-2/minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.2e-06 + }, "bedrock/us-east-2/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -7995,6 +8163,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "bedrock/us-west-2/minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "output_cost_per_token": 1.2e-06 + }, "bedrock/us-west-2/moonshotai.kimi-k2-thinking": { "input_cost_per_token": 6e-07, "litellm_provider": "bedrock", @@ -21292,6 +21474,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "minimax.minimax-m2.5": { + "input_cost_per_token": 3e-07, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 1000000, + "max_output_tokens": 8192, + "max_tokens": 8192, + "mode": "chat", + "output_cost_per_token": 1.2e-06, + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "source": "https://aws.amazon.com/bedrock/pricing/" + }, "minimax/speech-02-hd": { "input_cost_per_character": 0.0001, "litellm_provider": "minimax", @@ -23111,6 +23307,20 @@ "source": "https://aws.amazon.com/bedrock/pricing/", "supports_native_structured_output": true }, + "nvidia.nemotron-super-3-120b": { + "input_cost_per_token": 1.5e-07, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 256000, + "max_output_tokens": 32768, + "max_tokens": 32768, + "mode": "chat", + "output_cost_per_token": 6.5e-07, + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true + }, "o1": { "cache_read_input_token_cost": 7.5e-06, "input_cost_per_token": 1.5e-05, @@ -32726,6 +32936,20 @@ "supports_tool_choice": true, "source": "https://aws.amazon.com/bedrock/pricing/" }, + "zai.glm-5": { + "input_cost_per_token": 1e-06, + "litellm_provider": "bedrock_converse", + "max_input_tokens": 200000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "output_cost_per_token": 3.2e-06, + "source": "https://aws.amazon.com/bedrock/pricing/", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_system_messages": true, + "supports_tool_choice": true + }, "zai/glm-5": { "cache_creation_input_token_cost": 0, "cache_read_input_token_cost": 2e-07, From a6dfd02610bf3e4a5b94ab1a96d0be37b09d4203 Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Fri, 3 Apr 2026 06:28:52 +0200 Subject: [PATCH 30/32] fix(guardrails): return HTTP 400 instead of 500 for Model Armor streaming blocks (#24693) When Model Armor blocks a streaming response, it correctly raises HTTPException(status_code=400) but create_response() catches it with a bare except Exception and hardcodes a 500 response, discarding the original status code. Fix create_response() to preserve status_code from HTTPException instead of hardcoding 500. Also update Model Armor's streaming hook to yield an SSE error event instead of raising (matching the Prisma Airs pattern), and fix make_model_armor_request() to return 400 for upstream API failures instead of passing through the upstream status code. --- litellm/proxy/common_request_processing.py | 11 +- .../model_armor/model_armor.py | 23 +++- .../guardrail_hooks/test_model_armor.py | 125 +++++++++++++++++- .../proxy/test_common_request_processing.py | 29 +++- 4 files changed, 179 insertions(+), 9 deletions(-) diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index 386b9d27723..09200c96841 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -221,16 +221,21 @@ async def create_response( f"Error consuming first chunk from generator: {e}" ) - # Fallback to a generic error stream + # Preserve status code from HTTPException (e.g., guardrail blocks) + error_status = getattr(e, "status_code", status.HTTP_500_INTERNAL_SERVER_ERROR) + error_detail = getattr(e, "detail", "Error processing stream start") + if not isinstance(error_detail, str): + error_detail = str(error_detail) + async def error_gen_message() -> AsyncGenerator[str, None]: - yield f"data: {json.dumps({'error': {'message': 'Error processing stream start', 'code': status.HTTP_500_INTERNAL_SERVER_ERROR}})}\n\n" + yield f"data: {json.dumps({'error': {'message': error_detail, 'code': error_status}})}\n\n" yield "data: [DONE]\n\n" return StreamingResponse( error_gen_message(), media_type=media_type, headers=headers, - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=error_status, ) async def combined_generator() -> AsyncGenerator[str, None]: diff --git a/litellm/proxy/guardrails/guardrail_hooks/model_armor/model_armor.py b/litellm/proxy/guardrails/guardrail_hooks/model_armor/model_armor.py index 2d3f048f81b..3ee8e6a27bd 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/model_armor/model_armor.py +++ b/litellm/proxy/guardrails/guardrail_hooks/model_armor/model_armor.py @@ -14,6 +14,8 @@ from fastapi import HTTPException if TYPE_CHECKING: from litellm.types.proxy.guardrails.guardrail_hooks.base import GuardrailConfigModel +import json + import litellm from litellm._logging import verbose_proxy_logger from litellm.caching import DualCache @@ -203,8 +205,8 @@ class ModelArmorGuardrail(CustomGuardrail, VertexBase): response.text, ) raise HTTPException( - status_code=response.status_code, - detail=f"Model Armor API error: {response.text}", + status_code=400, + detail=f"Model Armor API error (upstream {response.status_code}): {response.text}", ) json_response = response.json() @@ -746,8 +748,21 @@ class ModelArmorGuardrail(CustomGuardrail, VertexBase): yield chunk return - except HTTPException: - raise + except HTTPException as e: + # Yield error as SSE event so create_response() detects it and + # returns a proper JSON error response with the correct status code. + # (Raising from a generator hits create_response's generic except → 500.) + detail = ( + e.detail if isinstance(e.detail, dict) else {"message": str(e.detail)} + ) + error_value = detail.get("error", detail) + if isinstance(error_value, dict): + error_obj = dict(error_value) + else: + error_obj = {"message": str(error_value)} + error_obj["code"] = e.status_code + yield f"data: {json.dumps({'error': error_obj})}\n\n" + return except Exception as e: verbose_proxy_logger.error( "Model Armor streaming error: %s", str(e), exc_info=True diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_model_armor.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_model_armor.py index 8080491f662..97ca55073df 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_model_armor.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_model_armor.py @@ -380,8 +380,9 @@ async def test_model_armor_api_error_handling(): call_type="completion" ) - assert exc_info.value.status_code == 500 + assert exc_info.value.status_code == 400 assert "Model Armor API error" in str(exc_info.value.detail) + assert "upstream 500" in str(exc_info.value.detail) @pytest.mark.asyncio @@ -485,6 +486,128 @@ async def test_model_armor_streaming_response(): assert len(result_chunks) > 0 mock_post.assert_called() +@pytest.mark.asyncio +async def test_model_armor_streaming_block_yields_sse_error(): + """Test that streaming content block yields SSE error event instead of raising HTTPException.""" + mock_user_api_key_dict = UserAPIKeyAuth() + + guardrail = ModelArmorGuardrail( + template_id="test-template", + project_id="test-project", + location="us-central1", + guardrail_name="model-armor-test", + ) + + # Mock Model Armor API response that triggers a block (SDP MATCH_FOUND) + mock_response = AsyncMock() + mock_response.status_code = 200 + mock_response.json = AsyncMock( + return_value={ + "sanitizationResult": { + "filterMatchState": "MATCH_FOUND", + "filterResults": { + "sdp": { + "sdpFilterResult": { + "inspectResult": { + "matchState": "MATCH_FOUND", + "findings": [ + { + "infoType": "PASSWORD", + "likelihood": "VERY_LIKELY", + } + ], + } + } + } + }, + } + } + ) + + guardrail._ensure_access_token_async = AsyncMock( + return_value=("test-token", "test-project") + ) + + with patch.object( + guardrail.async_handler, "post", AsyncMock(return_value=mock_response) + ): + + async def mock_stream(): + chunks = [ + litellm.ModelResponseStream( + choices=[ + litellm.types.utils.StreamingChoices( + delta=litellm.types.utils.Delta( + content="My password is " + ) + ) + ] + ), + litellm.ModelResponseStream( + choices=[ + litellm.types.utils.StreamingChoices( + delta=litellm.types.utils.Delta(content="hunter2") + ) + ] + ), + ] + for chunk in chunks: + yield chunk + + request_data = { + "model": "gpt-4", + "messages": [{"role": "user", "content": "What's your password?"}], + "metadata": {"guardrails": ["model-armor-test"]}, + } + + result_chunks = [] + async for chunk in guardrail.async_post_call_streaming_iterator_hook( + user_api_key_dict=mock_user_api_key_dict, + response=mock_stream(), + request_data=request_data, + ): + result_chunks.append(chunk) + + # Should yield exactly one SSE error event (not raise HTTPException) + assert len(result_chunks) == 1 + error_data = json.loads(result_chunks[0].removeprefix("data: ")) + assert "error" in error_data + assert error_data["error"]["code"] == 400 + + +@pytest.mark.asyncio +async def test_model_armor_api_failure_returns_400(): + """Test that Model Armor API failures raise HTTP 400, not the upstream status code.""" + guardrail = ModelArmorGuardrail( + template_id="test-template", + project_id="test-project", + location="us-central1", + guardrail_name="model-armor-test", + ) + + # Mock a 500 response from the Model Armor GCP API + mock_response = AsyncMock() + mock_response.status_code = 500 + mock_response.text = "Internal Server Error" + + guardrail._ensure_access_token_async = AsyncMock( + return_value=("test-token", "test-project") + ) + + with patch.object( + guardrail.async_handler, "post", AsyncMock(return_value=mock_response) + ): + with pytest.raises(HTTPException) as exc_info: + await guardrail.make_model_armor_request( + content="test content", + source="user_prompt", + ) + + # Should be 400, NOT the upstream 500 + assert exc_info.value.status_code == 400 + assert "upstream 500" in str(exc_info.value.detail) + + def test_model_armor_ui_friendly_name(): """Test the UI-friendly name of the Model Armor guardrail""" from litellm.types.proxy.guardrails.guardrail_hooks.model_armor import ( diff --git a/tests/test_litellm/proxy/test_common_request_processing.py b/tests/test_litellm/proxy/test_common_request_processing.py index 45ec4b726a8..781b559651f 100644 --- a/tests/test_litellm/proxy/test_common_request_processing.py +++ b/tests/test_litellm/proxy/test_common_request_processing.py @@ -4,7 +4,7 @@ from typing import AsyncGenerator from unittest.mock import AsyncMock, MagicMock, patch import pytest -from fastapi import Request, status +from fastapi import HTTPException, Request, status from fastapi.responses import JSONResponse, StreamingResponse import litellm @@ -899,6 +899,33 @@ class TestCommonRequestProcessingHelpers: assert content[0] == f"data: {json.dumps(expected_error_data)}\n\n" assert content[1] == "data: [DONE]\n\n" + async def test_create_streaming_response_generator_raises_http_exception( + self, + ): + """ + Test that when a generator raises HTTPException, the response preserves + the original status code instead of hardcoding 500. + """ + mock_gen = AsyncMock() + mock_gen.__anext__.side_effect = HTTPException( + status_code=400, detail="Content blocked by guardrail" + ) + + response = await create_response(mock_gen, "text/event-stream", {}) + assert response.status_code == 400 + content = await self.consume_stream(response) + import json + + expected_error_data = { + "error": { + "message": "Content blocked by guardrail", + "code": 400, + } + } + assert len(content) == 2 + assert content[0] == f"data: {json.dumps(expected_error_data)}\n\n" + assert content[1] == "data: [DONE]\n\n" + async def test_create_streaming_response_first_chunk_error_string_code(self): """ Test that when the first chunk contains a string error code, a JSON error response is returned From 50f4fdea3e4a0d2666c7100e1ff5ebb70e0d0c7a Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Thu, 2 Apr 2026 21:43:42 -0700 Subject: [PATCH 31/32] =?UTF-8?q?bump:=20version=201.83.0=20=E2=86=92=201.?= =?UTF-8?q?83.1=20(#25054)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ed9b0b8c57f..90b88165e86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "litellm" -version = "1.83.0" +version = "1.83.1" description = "Library to easily interface with LLM API providers" authors = ["BerriAI"] license = "MIT" @@ -181,7 +181,7 @@ requires = ["poetry-core", "wheel"] build-backend = "poetry.core.masonry.api" [tool.commitizen] -version = "1.83.0" +version = "1.83.1" version_files = [ "pyproject.toml:^version" ] From d4a3a5e530422d6ccd4dff82637ca275aa4e507d Mon Sep 17 00:00:00 2001 From: mubashir1osmani Date: Fri, 3 Apr 2026 00:51:21 -0400 Subject: [PATCH 32/32] fix gpt-5.4 pricing (#24748) --- model_prices_and_context_window.json | 29 +++++++--------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 4072aab6544..71918ed049b 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -18847,13 +18847,11 @@ "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_flex": 1.3e-07, "cache_read_input_token_cost_priority": 5e-07, - "cache_read_input_token_cost_above_272k_tokens_priority": 1e-06, "input_cost_per_token": 2.5e-06, "input_cost_per_token_above_272k_tokens": 5e-06, "input_cost_per_token_flex": 1.25e-06, "input_cost_per_token_batches": 1.25e-06, "input_cost_per_token_priority": 5e-06, - "input_cost_per_token_above_272k_tokens_priority": 1e-05, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, @@ -18863,8 +18861,7 @@ "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_flex": 7.5e-06, "output_cost_per_token_batches": 7.5e-06, - "output_cost_per_token_priority": 2.25e-05, - "output_cost_per_token_above_272k_tokens_priority": 3.375e-05, + "output_cost_per_token_priority": 3e-05, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -18897,13 +18894,11 @@ "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_flex": 1.3e-07, "cache_read_input_token_cost_priority": 5e-07, - "cache_read_input_token_cost_above_272k_tokens_priority": 1e-06, "input_cost_per_token": 2.5e-06, "input_cost_per_token_above_272k_tokens": 5e-06, "input_cost_per_token_flex": 1.25e-06, "input_cost_per_token_batches": 1.25e-06, "input_cost_per_token_priority": 5e-06, - "input_cost_per_token_above_272k_tokens_priority": 1e-05, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, @@ -18913,8 +18908,7 @@ "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_flex": 7.5e-06, "output_cost_per_token_batches": 7.5e-06, - "output_cost_per_token_priority": 2.25e-05, - "output_cost_per_token_above_272k_tokens_priority": 3.375e-05, + "output_cost_per_token_priority": 3e-05, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -18942,14 +18936,10 @@ "gpt-5.4-pro": { "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, - "cache_read_input_token_cost_priority": 6e-06, - "cache_read_input_token_cost_above_272k_tokens_priority": 1.2e-05, "input_cost_per_token": 3e-05, "input_cost_per_token_above_272k_tokens": 6e-05, "input_cost_per_token_flex": 1.5e-05, "input_cost_per_token_batches": 1.5e-05, - "input_cost_per_token_priority": 6e-05, - "input_cost_per_token_above_272k_tokens_priority": 0.00012, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, @@ -18959,8 +18949,6 @@ "output_cost_per_token_above_272k_tokens": 0.00027, "output_cost_per_token_flex": 9e-05, "output_cost_per_token_batches": 9e-05, - "output_cost_per_token_priority": 0.00027, - "output_cost_per_token_above_272k_tokens_priority": 0.000405, "supported_endpoints": [ "/v1/responses", "/v1/batch" @@ -18991,14 +18979,10 @@ "gpt-5.4-pro-2026-03-05": { "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, - "cache_read_input_token_cost_priority": 6e-06, - "cache_read_input_token_cost_above_272k_tokens_priority": 1.2e-05, "input_cost_per_token": 3e-05, "input_cost_per_token_above_272k_tokens": 6e-05, "input_cost_per_token_flex": 1.5e-05, "input_cost_per_token_batches": 1.5e-05, - "input_cost_per_token_priority": 6e-05, - "input_cost_per_token_above_272k_tokens_priority": 0.00012, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, @@ -19008,8 +18992,6 @@ "output_cost_per_token_above_272k_tokens": 0.00027, "output_cost_per_token_flex": 9e-05, "output_cost_per_token_batches": 9e-05, - "output_cost_per_token_priority": 0.00027, - "output_cost_per_token_above_272k_tokens_priority": 0.000405, "supported_endpoints": [ "/v1/responses", "/v1/batch" @@ -19039,11 +19021,13 @@ }, "gpt-5.4-mini": { "cache_read_input_token_cost": 7.5e-08, - "cache_read_input_token_cost_flex": 1e-08, - "cache_read_input_token_cost_batches": 3.8e-08, + "cache_read_input_token_cost_flex": 3.75e-08, + "cache_read_input_token_cost_batches": 3.75e-08, + "cache_read_input_token_cost_priority": 1.5e-07, "input_cost_per_token": 7.5e-07, "input_cost_per_token_flex": 3.75e-07, "input_cost_per_token_batches": 3.75e-07, + "input_cost_per_token_priority": 1.5e-06, "litellm_provider": "openai", "max_input_tokens": 272000, "max_output_tokens": 128000, @@ -19052,6 +19036,7 @@ "output_cost_per_token": 4.5e-06, "output_cost_per_token_flex": 2.25e-06, "output_cost_per_token_batches": 2.25e-06, + "output_cost_per_token_priority": 9e-06, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch",