diff --git a/ai-services/Makefile b/ai-services/Makefile index 44d6e80e78..3845eaf418 100644 --- a/ai-services/Makefile +++ b/ai-services/Makefile @@ -1,6 +1,6 @@ REGISTRY ?= icr.io/ai-services-private IMAGE = ai-services -TAG ?= v0.0.443 +TAG ?= v0.0.444 CONTAINER_BUILDER ?= podman CREDS_ARG := $(if $(and $(REGISTRY_USER),$(REGISTRY_PASSWORD)),--creds="$(REGISTRY_USER):$(REGISTRY_PASSWORD)") diff --git a/ai-services/assets/applications/rag-cpu/podman/values.yaml b/ai-services/assets/applications/rag-cpu/podman/values.yaml index 888fddbec3..2b56fb565b 100644 --- a/ai-services/assets/applications/rag-cpu/podman/values.yaml +++ b/ai-services/assets/applications/rag-cpu/podman/values.yaml @@ -104,7 +104,7 @@ litellm: # @description Enable LiteLLM proxy for remote LLM service. When true, uses LiteLLM with WatsonX; when false, uses local vLLM server. Default: false enable: false # @hidden - image: icr.io/ai-services-cicd/litellm:v1.101.2-0 + image: icr.io/ai-services-cicd/litellm:v1.106.4-0 # @description WatsonX API Key for LiteLLM integration. Required when litellm.enable is true. watsonxApiKey: "" # @description WatsonX Project ID for LiteLLM integration. Required when litellm.enable is true. diff --git a/ai-services/assets/catalog/openshift/values.yaml b/ai-services/assets/catalog/openshift/values.yaml index 0c3eb1d0f1..1fc69f47b4 100644 --- a/ai-services/assets/catalog/openshift/values.yaml +++ b/ai-services/assets/catalog/openshift/values.yaml @@ -9,7 +9,7 @@ ui: cpu: "500m" backend: - image: icr.io/ai-services-cicd/ai-services:v0.0.443 + image: icr.io/ai-services-cicd/ai-services:v0.0.444 runtime: "openshift" adminPasswordHash: "" # @generate:password length=32, special=false diff --git a/ai-services/assets/catalog/podman/values.yaml b/ai-services/assets/catalog/podman/values.yaml index 33015c4d7d..778efc490f 100644 --- a/ai-services/assets/catalog/podman/values.yaml +++ b/ai-services/assets/catalog/podman/values.yaml @@ -4,7 +4,7 @@ ui: backend: port: "" - image: icr.io/ai-services-cicd/ai-services:v0.0.443 + image: icr.io/ai-services-cicd/ai-services:v0.0.444 runtime: "" adminPasswordHash: "" # @generate:password length=32, special=false diff --git a/ai-services/assets/components/llm/watsonx/openshift/values.yaml b/ai-services/assets/components/llm/watsonx/openshift/values.yaml index f5ee8b5345..275280d737 100644 --- a/ai-services/assets/components/llm/watsonx/openshift/values.yaml +++ b/ai-services/assets/components/llm/watsonx/openshift/values.yaml @@ -1,4 +1,4 @@ -image: "icr.io/ai-services-cicd/litellm:v1.101.2-0" +image: "icr.io/ai-services-cicd/litellm:v1.106.4-0" model: "ibm/granite-4-h-small" watsonxApiKey: "" watsonxProjectId: "" diff --git a/ai-services/assets/components/llm/watsonx/podman/values.yaml b/ai-services/assets/components/llm/watsonx/podman/values.yaml index 888f299da6..ae9a5cf3f9 100644 --- a/ai-services/assets/components/llm/watsonx/podman/values.yaml +++ b/ai-services/assets/components/llm/watsonx/podman/values.yaml @@ -1,4 +1,4 @@ -image: "icr.io/ai-services-cicd/litellm:v1.101.2-0" +image: "icr.io/ai-services-cicd/litellm:v1.106.4-0" model: "ibm/granite-4-h-small" watsonxApiKey: "" watsonxProjectId: "" diff --git a/ai-services/assets/worker/openshift/values.yaml b/ai-services/assets/worker/openshift/values.yaml index 0a2b7cef0b..fc4ac27c44 100644 --- a/ai-services/assets/worker/openshift/values.yaml +++ b/ai-services/assets/worker/openshift/values.yaml @@ -1,5 +1,5 @@ worker: - image: icr.io/ai-services-cicd/ai-services:v0.0.443 + image: icr.io/ai-services-cicd/ai-services:v0.0.444 runtime: "openshift" token: "" gatewayAddr: "" diff --git a/ai-services/assets/worker/podman/values.yaml b/ai-services/assets/worker/podman/values.yaml index 805102bdbd..16251fec18 100644 --- a/ai-services/assets/worker/podman/values.yaml +++ b/ai-services/assets/worker/podman/values.yaml @@ -1,5 +1,5 @@ worker: - image: icr.io/ai-services-cicd/ai-services:v0.0.443 + image: icr.io/ai-services-cicd/ai-services:v0.0.444 runtime: "podman" token: "" gatewayAddr: "" diff --git a/images/litellm/Containerfile b/images/litellm/Containerfile index f8a7fddb9b..891652f10e 100644 --- a/images/litellm/Containerfile +++ b/images/litellm/Containerfile @@ -1,87 +1,143 @@ -# Builder stage -FROM registry.access.redhat.com/ubi9/ubi:9.8 as builder +#### Base stage: shared build dependencies for the parallel stages below +FROM registry.access.redhat.com/ubi9/ubi:9.8 as base -ARG VERSION=${VERSION} +ARG DNF_FLAGS="--disablerepo=* --enablerepo=ubi-9-baseos-rpms --enablerepo=ubi-9-appstream-rpms" +ARG TARGETARCH +ARG RUST_VERSION +ARG PYTHON_VERSION # 1. Install heavy build dependencies (gcc, rust, etc.) -RUN dnf -y update && \ - dnf -y install \ - wget \ +# Derive RPM_ARCH, NODE_ARCH and SKIP_CHECKSUM from the builder-provided TARGETARCH. +# SKIP_CHECKSUM=1 for non-ppc64le arches since NODE_SHA256 is only set for ppc64le. +RUN case "${TARGETARCH}" in \ + x86_64|amd64) RPM_ARCH=x86_64; NODE_ARCH=x64; SKIP_CHECKSUM=1; PROTOC_ARCH=x86_64 ;; \ + aarch64|arm64) RPM_ARCH=aarch64; NODE_ARCH=arm64; SKIP_CHECKSUM=1; PROTOC_ARCH=aarch_64 ;; \ + ppc64le) RPM_ARCH=ppc64le; NODE_ARCH=ppc64le; SKIP_CHECKSUM=0; PROTOC_ARCH=ppcle_64 ;; \ + *) RPM_ARCH="${TARGETARCH}"; NODE_ARCH="${TARGETARCH}"; SKIP_CHECKSUM=1; PROTOC_ARCH="${TARGETARCH}" ;; \ + esac && \ + echo "NODE_ARCH=${NODE_ARCH}" > /tmp/arch_env && \ + echo "PROTOC_ARCH=${PROTOC_ARCH}" >> /tmp/arch_env && \ + echo "SKIP_CHECKSUM=${SKIP_CHECKSUM}" >> /tmp/arch_env && \ + dnf update ${DNF_FLAGS} -y && \ + dnf install ${DNF_FLAGS} -y \ patch \ - python3.12 \ - python3.12-pip \ - python3.12-devel \ + python${PYTHON_VERSION} \ + python${PYTHON_VERSION}-pip \ + python${PYTHON_VERSION}-devel \ gcc \ gcc-c++ \ openssl-devel \ - zlib-devel && \ + zlib-devel \ + git \ + unzip && \ dnf clean all +# 2. Install rust toolchain (shared by the wheels and prisma-engines stages) +# RUSTC_BOOTSTRAP is needed by both the litellm wheel builds and the prisma engines +ENV RUSTC_BOOTSTRAP=1 \ + PATH="/root/.cargo/bin:${PATH}" +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \ + rustup install ${RUST_VERSION} && \ + rustup default ${RUST_VERSION} + WORKDIR /build -COPY pre-requirements.txt patches ./ +#### Litellm wheels stage (runs in parallel with the prisma-engines stage) +FROM base as wheels -# 2. Install Pre-requistes -RUN python3.12 -m pip install -r pre-requirements.txt \ - --extra-index-url=https://wheels.developerfirst.ibm.com/ppc64le/linux/ \ - --prefer-binary +ARG VERSION +ARG LITELLM_SHA256 +ARG PYTHON_VERSION +ENV PYTHON_VERSION=${PYTHON_VERSION} \ + UV_PYTHON=${PYTHON_VERSION} -# 3. Set compiler variables for ppc64le -ENV RUSTC_BOOTSTRAP=1 \ - GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1 \ - GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1 - -# 4. Download litellm & patch it -RUN wget https://github.com/BerriAI/litellm/archive/refs/tags/v${VERSION}.tar.gz >/dev/null -RUN tar -xzf v${VERSION}.tar.gz && \ - cd litellm-${VERSION} && \ - patch -p1 pyproject.toml < ../pyproject-toml.patch && \ - patch -p1 < ../watsonx-passthrough.patch && \ - uv lock && \ -# 5. Export dependencies to a requirements.txt file \ - uv export --no-hashes --no-dev \ - --extra proxy \ - --extra semantic-router \ - -o requirements.txt && \ - cat requirements.txt - -WORKDIR /build/litellm-${VERSION} - -# 6. Compile all dependencies into .whl files +COPY pre-requirements.txt \ + patches/litellm/build-litellm.sh \ + patches/litellm/*.patch \ + ./ + +# 3. Download, patch and compile litellm and its dependencies into wheels RUN --mount=type=cache,target=/root/.cache/pip \ - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | /usr/bin/sh -s -- -y && \ - source "$HOME/.cargo/env" && rustup install 1.94.1 && rustup default 1.94.1 && \ - python3.12 -m pip wheel -r requirements.txt \ - -w /wheels \ - --extra-index-url=https://wheels.developerfirst.ibm.com/ppc64le/linux/ \ - --prefer-binary && \ - uv build --wheel --out-dir /wheels - -# Runtime Stage -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8 + bash build-litellm.sh -ARG VERSION=${VERSION} +#### Prisma engines stage (runs in parallel with the wheels stage) +FROM base as prisma-engines -ENV DISABLE_ADMIN_UI=true \ - LITELLM_NON_ROOT=true +ARG PROTOC_VERSION +ARG PROTOC_SHA256 -RUN --mount=type=bind,from=builder,source=/wheels,target=/wheels,ro \ - microdnf -y update && \ - microdnf -y install \ - python3.12 \ - python3.12-pip && \ - python3.12 -m pip install --no-cache-dir --no-index \ - --find-links=/wheels \ - litellm[proxy,semantic-router]==${VERSION} && \ - python3.12 -m pip cache purge && \ - microdnf remove -y python3.12-pip && \ - microdnf clean all +COPY patches/prisma ./prisma -USER 1001 +# 4. Patch & build Prisma engines +RUN PROTOC_VERSION=${PROTOC_VERSION} PROTOC_SHA256=${PROTOC_SHA256} \ + bash prisma/build-prisma.sh + +#### Builder stage: needs both the wheels and the compiled engines +FROM wheels as builder + +ARG NODE_VERSION +ARG NODE_SHA256 + +WORKDIR /build +COPY --from=prisma-engines /build/prisma-engines/target/release/query-engine prisma-engines/target/release/query-engine +COPY --from=prisma-engines /build/prisma-engines/target/release/schema-engine prisma-engines/target/release/schema-engine +COPY --from=prisma-engines /build/prisma-engines/target/release/libquery_engine.so prisma-engines/target/release/libquery_engine.so +COPY install-prisma-cli.sh ./ + +# 5. Install Node.js and bake Prisma CLI +RUN NODE_VERSION=${NODE_VERSION} NODE_SHA256=${NODE_SHA256} \ + bash install-prisma-cli.sh + +#### Runtime Stage +FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8 + +ARG VERSION=${VERSION} +ARG PYTHON_VERSION +ARG DNF_FLAGS="--disablerepo=* --enablerepo=ubi-9-baseos-rpms --enablerepo=ubi-9-appstream-rpms" + +ENV LITELLM_NON_ROOT=true \ + #pyroscope isn't supported on ppc64le + LITELLM_ENABLE_PYROSCOPE=false \ + LITELLM_UI_PATH=/app/ui \ + LITELLM_ASSETS_PATH=/app/assets \ + PRISMA_QUERY_ENGINE_LIBRARY=/app/prisma/libquery_engine-rhel-openssl-3.0.x.so.node \ + PRISMA_QUERY_ENGINE_BINARY=/app/prisma/query-engine \ + PRISMA_SCHEMA_ENGINE_BINARY=/app/prisma/schema-engine \ + PRISMA_ENGINES_CHECKSUM_IGNORE_WARNING="true" \ + PRISMA_BINARY_CACHE_DIR=/app/prisma/binaries \ + PRISMA_CLI_PATH=/app/prisma/binaries/node_modules/.bin/prisma \ + PRISMA_CLI_QUERY_ENGINE_TYPE=binary \ + PRISMA_OFFLINE_MODE=true \ + HOME=/app \ + PATH="/app/node/bin:/app/.venv/bin:${PATH}" WORKDIR /app COPY config ./ +COPY --from=builder /build/prisma-engines/target/release/query-engine prisma/query-engine +COPY --from=builder /build/prisma-engines/target/release/schema-engine prisma/schema-engine +COPY --from=builder /build/prisma-engines/target/release/libquery_engine.so prisma/libquery_engine-rhel-openssl-3.0.x.so.node +COPY --from=builder /build/litellm-${VERSION}/schema.prisma ./ +COPY --from=builder /build/prisma/binaries prisma/binaries +COPY --from=builder /usr/local/bin/node /app/node/bin/node + +RUN --mount=type=bind,from=builder,source=/wheels,target=/wheels,ro \ + microdnf -y update ${DNF_FLAGS} && \ + microdnf -y install ${DNF_FLAGS} \ + python${PYTHON_VERSION} \ + libatomic \ + libsndfile \ + openssl && \ + microdnf clean all && \ + useradd -u 1001 -M -d /app -s /sbin/nologin litellm && \ + python${PYTHON_VERSION} -m venv /app/.venv && \ + /app/.venv/bin/pip install --no-cache-dir --no-index --find-links=/wheels \ + litellm[proxy,semantic-router]==${VERSION} && \ + prisma generate --schema=/app/schema.prisma && \ + rm -rf /app/.npm /tmp/node-compile-cache && \ + chown -R 1001:1001 /app + +USER 1001 EXPOSE 4000 diff --git a/images/litellm/Makefile b/images/litellm/Makefile index a914c80dc6..2d964b40c0 100644 --- a/images/litellm/Makefile +++ b/images/litellm/Makefile @@ -1,15 +1,74 @@ REGISTRY?=icr.io/ai-services-private IMAGE=litellm -# 1. Must run update-patch after updating the Litellm version -# 2. Manually regenerate the patches/watsonx-passthrough.patch -LITELLM_VERSION?=1.101.2 +# When updating LITELLM_VERSION: +# 1. Run update-patch to regenerate patches/litellm/pyproject-toml.patch +# 2. Manually update patches/litellm/watsonx-passthrough.patch if the patched file changed upstream +# 3. Run verify-patch to confirm all patches apply cleanly +# 4. Run update-checksums to regenerate the checksums +LITELLM_VERSION?=1.106.4 +LITELLM_SHA256?=dc58da933f25e8efec12348a4821b71e15e358d97093821576073fee37c49589 IMAGE_REVISION?=0 +PYTHON_VERSION?=3.14 +# Node.js version for baking Prisma CLI — Active LTS version +NODE_VERSION?=24.21.0 +NODE_SHA256?=51c5d53066ee92920b61783b03b06ecb99f3661160f7b15ca77e8474115a67bc +# Rust toolchain version used to build the litellm wheels and the prisma engines +RUST_VERSION?=1.94.1 +# protoc version from https://github.com/protocolbuffers/protobuf/releases +# PROTOC_SHA256 is the sha256 of protoc-$(PROTOC_VERSION)-linux-ppcle_64.zip +PROTOC_VERSION?=34.1 +PROTOC_SHA256?=9160f1336e266dd0b389a29c4ffabded6cc9b80ab29f2da423106d6fe75b2ce2 TAG?=v$(LITELLM_VERSION)-$(IMAGE_REVISION) CREDS_ARG := $(if $(and $(REGISTRY_USER),$(REGISTRY_PASSWORD)),--creds="$(REGISTRY_USER):$(REGISTRY_PASSWORD)") CONTAINER_BUILDER?=podman + +# Dev env vars — override on the command line or export before running +INSTRUCT_MODEL_NAME?=my-instruct-model +INSTRUCT_MODEL?=watsonx/ibm/granite-4-h-small +WATSONX_APIKEY?= +WATSONX_PROJECT_ID?= +WATSONX_URL?=https://us-south.ml.cloud.ibm.com +LITELLM_MASTER_KEY?=sk-0987612345 +DB_USER?=postgres +DB_PASSWORD?=devpassword +DB_HOST?=localhost +DB_PORT?=5432 +DB_NAME?=litellm +DATABASE_URL?=postgresql://$(DB_USER):$(DB_PASSWORD)@$(DB_HOST):$(DB_PORT)/$(DB_NAME) + +run: + $(CONTAINER_BUILDER) run -d \ + --name litellm-dev \ + --net host \ + -e INSTRUCT_MODEL_NAME="$(INSTRUCT_MODEL_NAME)" \ + -e INSTRUCT_MODEL="$(INSTRUCT_MODEL)" \ + -e WATSONX_APIKEY="$(WATSONX_APIKEY)" \ + -e WATSONX_PROJECT_ID="$(WATSONX_PROJECT_ID)" \ + -e WATSONX_URL="$(WATSONX_URL)" \ + -e LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" \ + -e DATABASE_URL="$(DATABASE_URL)" \ + $(REGISTRY)/$(IMAGE):$(TAG) \ + litellm -c /app/config.yaml --detailed_debug +.PHONY: run + +clean: + -$(CONTAINER_BUILDER) stop litellm-dev + -$(CONTAINER_BUILDER) rm litellm-dev +.PHONY: clean + build: - $(CONTAINER_BUILDER) build -t $(REGISTRY)/$(IMAGE):$(TAG) --build-arg VERSION=$(LITELLM_VERSION) . + $(CONTAINER_BUILDER) build -t $(REGISTRY)/$(IMAGE):$(TAG) \ + --jobs 2 \ + --build-arg VERSION=$(LITELLM_VERSION) \ + --build-arg LITELLM_SHA256=$(LITELLM_SHA256) \ + --build-arg PYTHON_VERSION=$(PYTHON_VERSION) \ + --build-arg NODE_VERSION=$(NODE_VERSION) \ + --build-arg NODE_SHA256=$(NODE_SHA256) \ + --build-arg RUST_VERSION=$(RUST_VERSION) \ + --build-arg PROTOC_VERSION=$(PROTOC_VERSION) \ + --build-arg PROTOC_SHA256=$(PROTOC_SHA256) \ + . .PHONY: build push: @@ -21,5 +80,23 @@ image-tag: .PHONY: image-tag update-patch: - cd ./patches && ./pyproject-toml.sh $(LITELLM_VERSION) + cd ./patches/litellm && ./pyproject-toml.sh $(LITELLM_VERSION) .PHONY: update-patch + +# Fetch the upstream source files for LITELLM_VERSION, apply each patch, and +# show the resulting diff so you can confirm the patches apply cleanly. +verify-patch: + ./patches/litellm/verify-patch.sh $(LITELLM_VERSION) +.PHONY: verify-patch + +update-checksums: + $(eval NEW_LITELLM_SHA256 := $(shell curl -fsSL https://github.com/BerriAI/litellm/archive/refs/tags/v$(LITELLM_VERSION).tar.gz | sha256sum | cut -d' ' -f1)) + $(eval NEW_NODE_SHA256 := $(shell curl -fsSL https://nodejs.org/dist/v$(NODE_VERSION)/node-v$(NODE_VERSION)-linux-ppc64le.tar.gz | sha256sum | cut -d' ' -f1)) + $(eval NEW_PROTOC_SHA256 := $(shell curl -fsSL https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)-linux-ppcle_64.zip | sha256sum | cut -d' ' -f1)) + sed -i "s|^LITELLM_SHA256?=.*|LITELLM_SHA256?=$(NEW_LITELLM_SHA256)|" $(MAKEFILE_LIST) + sed -i "s|^NODE_SHA256?=.*|NODE_SHA256?=$(NEW_NODE_SHA256)|" $(MAKEFILE_LIST) + sed -i "s|^PROTOC_SHA256?=.*|PROTOC_SHA256?=$(NEW_PROTOC_SHA256)|" $(MAKEFILE_LIST) + @echo "Updated LITELLM_SHA256 to $(NEW_LITELLM_SHA256)" + @echo "Updated NODE_SHA256 to $(NEW_NODE_SHA256)" + @echo "Updated PROTOC_SHA256 to $(NEW_PROTOC_SHA256)" +.PHONY: update-checksums diff --git a/images/litellm/config/config.yaml b/images/litellm/config/config.yaml index b4ce710aa6..2e0350c2b0 100644 --- a/images/litellm/config/config.yaml +++ b/images/litellm/config/config.yaml @@ -1,13 +1,6 @@ -model_list: - - model_name: "os.environ/INSTRUCT_MODEL_NAME" - litellm_params: - model: "os.environ/INSTRUCT_MODEL" - api_key: "os.environ/WATSONX_APIKEY" - project_id: "os.environ/WATSONX_PROJECT_ID" - base_url: "os.environ/WATSONX_URL" litellm_settings: callbacks: custom_callbacks.translator_instance general_settings: - pass_through_endpoints: - - path: "/tokenize" - target: http://localhost:8000/watsonx/ml/v1/text/tokenization + reject_clientside_metadata_tags: true +router_settings: + enable_tag_filtering: True diff --git a/images/litellm/install-prisma-cli.sh b/images/litellm/install-prisma-cli.sh new file mode 100755 index 0000000000..adf6439426 --- /dev/null +++ b/images/litellm/install-prisma-cli.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Installs Node.js and bakes the Prisma CLI into /build/prisma. +# Needs the litellm wheels (/wheels) and the compiled Prisma engines. +# Avoids nodeenv downloading Node at runtime, eliminating CVEs from bundled npm packages. +set -euo pipefail + +# Load arch env written by the base stage (NODE_ARCH, SKIP_CHECKSUM) +. /tmp/arch_env + +curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.gz" \ + -o /tmp/node.tar.gz +if [ "${SKIP_CHECKSUM}" != "1" ]; then + echo "${NODE_SHA256} /tmp/node.tar.gz" | sha256sum -c - +fi +tar -xz -C /usr/local --strip-components=1 -f /tmp/node.tar.gz +rm /tmp/node.tar.gz + +python${PYTHON_VERSION} -m pip install --no-cache-dir --no-index --find-links=/wheels prisma + +mkdir -p /build/prisma +HOME=/build/prisma \ +XDG_CACHE_HOME=/build/prisma/.cache \ +PRISMA_BINARY_CACHE_DIR=/build/prisma/binaries \ +PRISMA_QUERY_ENGINE_BINARY=/build/prisma-engines/target/release/query-engine \ +PRISMA_SCHEMA_ENGINE_BINARY=/build/prisma-engines/target/release/schema-engine \ +PRISMA_QUERY_ENGINE_LIBRARY=/build/prisma-engines/target/release/libquery_engine.so \ +PRISMA_ENGINES_CHECKSUM_IGNORE_WARNING=true \ +prisma version diff --git a/images/litellm/patches/litellm/build-litellm.sh b/images/litellm/patches/litellm/build-litellm.sh new file mode 100755 index 0000000000..e2e89754e8 --- /dev/null +++ b/images/litellm/patches/litellm/build-litellm.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Downloads and patches litellm, then compiles it and all its dependencies into +# wheels under /wheels. Independent of the prisma engines, so it runs in its own +# build stage. Expects VERSION and LITELLM_SHA256 in the environment. +set -euo pipefail + +cd /build + +# Compiler variables for ppc64le +export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1 +export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1 + +PYTHON_BIN="python${PYTHON_VERSION}" +export UV_PYTHON="${PYTHON_VERSION}" + +# 1. Install pre-requisites +"${PYTHON_BIN}" -m pip install -r pre-requirements.txt \ + --extra-index-url=https://wheels.developerfirst.ibm.com/ppc64le/linux/ \ + --prefer-binary + +# 2. Download litellm & patch it +curl -fsSL "https://github.com/BerriAI/litellm/archive/refs/tags/v${VERSION}.tar.gz" \ + -o "v${VERSION}.tar.gz" +echo "${LITELLM_SHA256} v${VERSION}.tar.gz" | sha256sum -c - +tar -xzf "v${VERSION}.tar.gz" +rm "v${VERSION}.tar.gz" + +cd "litellm-${VERSION}" +patch -p1 < ../pyproject-toml.patch +patch -p1 < ../watsonx-passthrough.patch + +uv lock + +# 3. Export dependencies to a requirements.txt file +uv export --no-hashes --no-dev \ + --extra proxy \ + --extra semantic-router \ + -o requirements.txt +cat requirements.txt + +# 4. Compile all dependencies into .whl files +"${PYTHON_BIN}" -m pip wheel -r requirements.txt \ + -w /wheels \ + --extra-index-url=https://wheels.developerfirst.ibm.com/ppc64le/linux/ \ + --prefer-binary +uv build --wheel --out-dir /wheels diff --git a/images/litellm/patches/litellm/pyproject-toml.patch b/images/litellm/patches/litellm/pyproject-toml.patch new file mode 100644 index 0000000000..449997171f --- /dev/null +++ b/images/litellm/patches/litellm/pyproject-toml.patch @@ -0,0 +1,59 @@ +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -3,7 +3,7 @@ + version = "1.106.4" + description = "Library to easily interface with LLM API providers" + readme = "README.md" +-requires-python = ">=3.10, <3.15" ++requires-python = ">=3.11, <3.15" + license = "MIT" + license-files = ["LICENSE"] + authors = [ +@@ -15,7 +15,7 @@ + # When changing a floor, verify it installs + imports on every supported + # Python with: `uv pip install --resolution=lowest-direct .` + "fastuuid>=0.14.0,<1.0", +- "filelock>=3.16.1,<4.0", ++ "filelock>=4.2.1", + "httpx[http2]>=0.28.0,<1.0", + "openai>=2.20.0,<3.0.0", + "python-dotenv>=1.0.0,<2.0", +@@ -79,15 +79,16 @@ + "httpx2>=2.5.0,<3", + "pydantic>=2.12.0,<3", + "litellm-proxy-extras==0.4.108", +- "litellm-enterprise==0.1.76.post1", ++ "litellm-enterprise==0.1.76.post1; platform_machine != 'ppc64le'", + "RestrictedPython>=8.5,<9.0", + "rich>=13.9.4,<14.0", + "InquirerPy>=0.3.4,<1.0", + "tomlkit>=0.13.3,<1.0", + "polars>=1.38.1,<2.0", + "soundfile>=0.12.1,<1.0", +- "pyroscope-io>=0.8.16,<1.0; sys_platform != 'win32'", ++ "pyroscope-io>=0.8.16,<1.0; sys_platform != 'win32' and platform_machine != 'ppc64le'", + "expression>=5.6.0,<6.0", ++ "prisma>=0.11.0,<1.0", + ] + # Thin client install for the `lite` CLI on developer laptops. The CLI's heavy + # imports are all guarded, so it runs on the base SDK plus these packages, and +--- a/packaging/litellm-core/pyproject.toml ++++ b/packaging/litellm-core/pyproject.toml +@@ -3,7 +3,7 @@ + version = "1.105.0" + description = "Library to easily interface with LLM API providers" + readme = "README.md" +-requires-python = ">=3.10, <3.15" ++requires-python = ">=3.11, <3.15" + license = "MIT" + license-files = ["LICENSE"] + authors = [ +@@ -11,7 +11,7 @@ + ] + dependencies = [ + "fastuuid>=0.14.0,<1.0", +- "filelock>=3.16.1,<4.0", ++ "filelock>=4.2.1", + "httpx[http2]>=0.28.0,<1.0", + "openai>=2.20.0,<3.0.0", + "python-dateutil>=2.8.2,<3.0", diff --git a/images/litellm/patches/litellm/pyproject-toml.sh b/images/litellm/patches/litellm/pyproject-toml.sh new file mode 100755 index 0000000000..8e0e124b7c --- /dev/null +++ b/images/litellm/patches/litellm/pyproject-toml.sh @@ -0,0 +1,152 @@ +#!/bin/bash +set -euo pipefail + +# Accept version as first argument, or exit with error +if [ -z "${1:-}" ]; then + echo "Error: Version argument required" + echo "Usage: $0 " + echo "Example: $0 1.84.0" + exit 1 +fi + +VERSION="$1" +BASE_URL="https://raw.githubusercontent.com/BerriAI/litellm/refs/tags/v${VERSION}" +PATCH_FILE="pyproject-toml.patch" + +TOML_FILES=( + "pyproject.toml" + "packaging/litellm-core/pyproject.toml" +) + +# --------------------------------------------------------------------------- +# 1. Packages that are unavailable on ppc64le — add platform_machine marker +# --------------------------------------------------------------------------- +PPC64LE_EXCLUDE_PACKAGES=( + "litellm-enterprise==" + "pyroscope-io>=" +) + +# --------------------------------------------------------------------------- +# 2. Extra packages to inject at the end of the [proxy] extras list +# Format: one package specifier per entry, e.g. "prisma>=0.11.0,<1.0" +# --------------------------------------------------------------------------- +EXTRA_PACKAGES=( + "prisma>=0.11.0,<1.0" +) + +# --------------------------------------------------------------------------- +# 3. Package version bumps — replace upstream specifier with our specifier +# Format: "old_specifier|new_specifier" +# e.g. "filelock>=3.16.1,<4.0|filelock>=4.2.1" +# --------------------------------------------------------------------------- +VERSION_BUMPS=( + "filelock>=3.16.1,<4.0|filelock>=4.2.1" + 'requires-python = ">=3.10|requires-python = ">=3.11' +) + +# --------------------------------------------------------------------------- + +echo "==================================================" +echo "Step 1: Downloading pyproject.toml files (v${VERSION})..." +echo "==================================================" + +for REL_PATH in "${TOML_FILES[@]}"; do + mkdir -p "$(dirname "$REL_PATH")" + URL="${BASE_URL}/${REL_PATH}" + curl --connect-timeout 10 --max-time 30 -fsSL "$URL" -o "$REL_PATH" + + if [ ! -s "$REL_PATH" ]; then + echo "Error: Failed to download $REL_PATH." + exit 1 + fi + echo "Successfully downloaded $REL_PATH." + cp "$REL_PATH" "${REL_PATH}.bkp" +done +echo "" + +echo "==================================================" +echo "Step 2: Adding ppc64le platform_machine markers..." +echo "==================================================" + +if [ "${#PPC64LE_EXCLUDE_PACKAGES[@]}" -gt 0 ]; then +for REL_PATH in "${TOML_FILES[@]}"; do + for PKG in "${PPC64LE_EXCLUDE_PACKAGES[@]}"; do + if grep -q "$PKG" "$REL_PATH"; then + echo "Patching in $REL_PATH: $PKG" + sed -i -E '/'"$PKG"'/ { + /;/ s/("[^"]+)(".*)/\1 and platform_machine != '\''ppc64le'\''\2/ + /;/! s/("[^"]+)(".*)/\1; platform_machine != '\''ppc64le'\''\2/ + }' "$REL_PATH" + fi + done +done +fi +echo "" + +echo "==================================================" +echo "Step 3: Injecting extra packages into [proxy]..." +echo "==================================================" + +if [ "${#EXTRA_PACKAGES[@]}" -gt 0 ]; then +for REL_PATH in "${TOML_FILES[@]}"; do + if grep -q '^proxy = \[' "$REL_PATH"; then + for PKG in "${EXTRA_PACKAGES[@]}"; do + if awk '/^proxy = \[/{in_proxy=1} /^\]/{in_proxy=0} in_proxy && index($0, "'"$PKG"'"){found=1} END{exit !found}' "$REL_PATH"; then + echo "Already present in $REL_PATH proxy block, skipping: $PKG" + else + echo "Injecting into $REL_PATH: $PKG" + awk -v pkg=" \"${PKG}\"," ' + /^proxy = \[/ { in_proxy = 1 } + in_proxy && /^\]/ { + print pkg + in_proxy = 0 + } + { print } + ' "$REL_PATH" > "$REL_PATH.tmp" + mv "$REL_PATH.tmp" "$REL_PATH" + fi + done + fi +done +fi +echo "" + +echo "==================================================" +echo "Step 4: Applying package version bumps..." +echo "==================================================" + +if [ "${#VERSION_BUMPS[@]}" -gt 0 ]; then +for REL_PATH in "${TOML_FILES[@]}"; do + for BUMP in "${VERSION_BUMPS[@]}"; do + OLD_STR="${BUMP%%|*}" + NEW_STR="${BUMP#*|}" + if grep -q "${OLD_STR}" "$REL_PATH"; then + echo "Bumping in $REL_PATH: ${OLD_STR} → ${NEW_STR}" + sed -i "s|${OLD_STR}|${NEW_STR}|g" "$REL_PATH" + fi + done +done +fi +echo "" + +echo "==================================================" +echo "Step 5: Generating patch file..." +echo "==================================================" + +> "$PATCH_FILE" +for REL_PATH in "${TOML_FILES[@]}"; do + diff -u --label "a/${REL_PATH}" "${REL_PATH}.bkp" \ + --label "b/${REL_PATH}" "${REL_PATH}" \ + >> "$PATCH_FILE" || true + rm -f "${REL_PATH}" "${REL_PATH}.bkp" +done +# Clean up empty packaging dir if created +rm -rf packaging + +echo "Patch file generated: ${PATCH_FILE}" +echo "" + +echo "==================================================" +echo "Process complete! Generated patch:" +echo "==================================================" +cat "$PATCH_FILE" diff --git a/images/litellm/patches/litellm/verify-patch.sh b/images/litellm/patches/litellm/verify-patch.sh new file mode 100755 index 0000000000..bc14d74524 --- /dev/null +++ b/images/litellm/patches/litellm/verify-patch.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -euo pipefail + +if [ -z "${1:-}" ]; then + echo "Error: Version argument required" + echo "Usage: $0 " + echo "Example: $0 1.106.2" + exit 1 +fi + +VERSION="$1" +BASE_URL="https://raw.githubusercontent.com/BerriAI/litellm/refs/tags/v${VERSION}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VERIFY_TMP="$(mktemp -d)" +trap 'rm -rf "$VERIFY_TMP"' EXIT + +FILES_TO_VERIFY=( + "pyproject.toml" + "packaging/litellm-core/pyproject.toml" + "litellm/proxy/pass_through_endpoints/pass_through_endpoints.py" +) + +echo "==> Fetching upstream sources for v${VERSION}..." +for REL_PATH in "${FILES_TO_VERIFY[@]}"; do + mkdir -p "${VERIFY_TMP}/orig/$(dirname "$REL_PATH")" + curl --connect-timeout 10 --max-time 30 -fsSL "${BASE_URL}/${REL_PATH}" \ + -o "${VERIFY_TMP}/orig/${REL_PATH}" +done + +cp -r "${VERIFY_TMP}/orig/." "${VERIFY_TMP}/patched/" + +echo "" +echo "==> Applying patches..." +patch -p1 -d "${VERIFY_TMP}/patched" < "${SCRIPT_DIR}/pyproject-toml.patch" \ + && echo " [OK] pyproject-toml.patch" \ + || echo " [FAIL] pyproject-toml.patch" + +patch -p1 -d "${VERIFY_TMP}/patched" < "${SCRIPT_DIR}/watsonx-passthrough.patch" \ + && echo " [OK] watsonx-passthrough.patch" \ + || echo " [FAIL] watsonx-passthrough.patch" + +echo "" +echo "==> Diff of patched files:" +for REL_PATH in "${FILES_TO_VERIFY[@]}"; do + diff -u "${VERIFY_TMP}/orig/${REL_PATH}" \ + "${VERIFY_TMP}/patched/${REL_PATH}" || true +done diff --git a/images/litellm/patches/watsonx-passthrough.patch b/images/litellm/patches/litellm/watsonx-passthrough.patch similarity index 58% rename from images/litellm/patches/watsonx-passthrough.patch rename to images/litellm/patches/litellm/watsonx-passthrough.patch index 3676557954..321f57fd08 100644 --- a/images/litellm/patches/watsonx-passthrough.patch +++ b/images/litellm/patches/litellm/watsonx-passthrough.patch @@ -1,27 +1,3 @@ -diff --git a/pyproject.toml b/pyproject.toml -index fc8415e5..51a4bd23 100644 ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -48,7 +48,7 @@ proxy = [ - "granian>=2.7.4,<3.0", - "uvloop>=0.22.1,<1.0; sys_platform != 'win32'", - "fastapi>=0.136.3,<1.0", -- "starlette>=1.0.1,<2.0", -+ "starlette>=1.3.1,<2.0", - "backoff>=2.2.1,<3.0", - "pyyaml>=6.0.3,<7.0", - "rq>=2.7.0,<3.0", -@@ -58,8 +58,8 @@ proxy = [ - "hiredis>=3.0.0,<4.0", - "apscheduler>=3.11.2,<4.0", - "fastapi-sso>=0.19.0,<1.0", -- "PyJWT>=2.13.0,<3.0", -- "python-multipart>=0.0.27,<1.0", -+ "PyJWT>=2.14.0,<3.0", -+ "python-multipart>=0.0.30,<1.0", - "cryptography>=49.0.0,<51.0", - "pynacl>=1.6.2,<2.0", - "websockets>=15.0.1,<16.0", diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index be669502..e63c75d0 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py diff --git a/images/litellm/patches/prisma/build-prisma.sh b/images/litellm/patches/prisma/build-prisma.sh new file mode 100755 index 0000000000..2d00bff7a9 --- /dev/null +++ b/images/litellm/patches/prisma/build-prisma.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Builds the Prisma engines (query-engine, schema-engine, libquery_engine). +# Independent of the litellm wheels, so it runs in its own build stage. +set -euo pipefail + +# Load arch env written by the base stage (PROTOC_ARCH, SKIP_CHECKSUM) +. /tmp/arch_env + +WORKDIR=/build + +# 1. Install protoc from GitHub releases +curl -fsSL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" \ + -o /tmp/protoc.zip +if [ "${SKIP_CHECKSUM}" != "1" ]; then + echo "${PROTOC_SHA256} /tmp/protoc.zip" | sha256sum -c - +fi +unzip -q /tmp/protoc.zip -d /tmp/protoc +install -m 0755 /tmp/protoc/bin/protoc /usr/local/bin/protoc +cp -r /tmp/protoc/include/* /usr/local/include/ +rm -rf /tmp/protoc /tmp/protoc.zip + +# 2. Patch & build Prisma engines (rust toolchain comes from the base stage) +cd "${WORKDIR}" +git clone --depth 1 --branch 5.4.2 https://github.com/prisma/prisma-engines.git +curl -sSL https://static.crates.io/crates/ring/ring-0.16.20.crate | tar -xvzf - + +cd "${WORKDIR}/ring-0.16.20" +patch -p1 < ../prisma/ring.patch + +cd "${WORKDIR}/prisma-engines" +export RUSTFLAGS="--cap-lints allow -A ambiguous_glob_imports" +patch -p1 < ../prisma/prisma.patch +cargo update -p time@0.3.25 +cargo build --release --bin query-engine +cargo build --release --bin schema-engine +cargo build --release -p query-engine-node-api diff --git a/images/litellm/patches/prisma/prisma.patch b/images/litellm/patches/prisma/prisma.patch new file mode 100644 index 0000000000..15cc01427d --- /dev/null +++ b/images/litellm/patches/prisma/prisma.patch @@ -0,0 +1,11 @@ +diff --git a/Cargo.toml b/Cargo.toml +index 77afa5e..a339284 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -83,3 +83,6 @@ opt-level = 's' # Optimize for size. + [profile.profiling] + inherits = "release" + debug = true ++ ++[patch.crates-io] ++ring = { path = "/build/ring-0.16.20" } diff --git a/images/litellm/patches/prisma/ring.patch b/images/litellm/patches/prisma/ring.patch new file mode 100644 index 0000000000..a3b565de4b --- /dev/null +++ b/images/litellm/patches/prisma/ring.patch @@ -0,0 +1,79 @@ +diff --git a/include/GFp/base.h b/include/GFp/base.h +index e18ee44..ea8286c 100644 +--- a/include/GFp/base.h ++++ b/include/GFp/base.h +@@ -89,6 +89,8 @@ + #define OPENSSL_MIPS64 + #elif defined(__wasm__) + #define OPENSSL_32_BIT ++#elif defined(__PPC64__) || defined(__ppc64__) || defined(__powerpc__) ++#define OPENSSL_64_BIT + #else + // Note BoringSSL only supports standard 32-bit and 64-bit two's-complement, + // little-endian architectures. Functions will not produce the correct answer +diff --git a/build.rs b/build.rs +index a5a8e19..8564d9d 100644 +--- a/build.rs ++++ b/build.rs +@@ -355,7 +355,7 @@ fn build_c_code(target: &Target, pregenerated: PathBuf, out_dir: &Path) { + let &(entry_arch, entry_os, _) = *entry; + entry_arch == target.arch && is_none_or_equals(entry_os, &target.os) + }) +- .unwrap(); ++ .unwrap_or(&("ppc64le", None, None)); + + let use_pregenerated = !target.is_git; + let warnings_are_errors = target.is_git; +diff --git a/src/rand.rs b/src/rand.rs +index 9d1864f..113c5b7 100644 +--- a/src/rand.rs ++++ b/src/rand.rs +@@ -217,6 +217,9 @@ mod sysrand_chunk { + #[cfg(target_arch = "x86_64")] + const SYS_GETRANDOM: c_long = 318; + ++ #[cfg(any(target_arch = "powerpc64le", target_arch = "powerpc", target_arch = "powerpc64"))] ++ const SYS_GETRANDOM: libc::c_long = 359; ++ + let chunk_len: c::size_t = dest.len(); + let r = unsafe { libc::syscall(SYS_GETRANDOM, dest.as_mut_ptr(), chunk_len, 0) }; + if r < 0 { +diff --git a/crypto/fipsmodule/aes/aes_nohw.c b/crypto/fipsmodule/aes/aes_nohw.c +index 19b019e7..0cb565d9 100644 +--- a/crypto/fipsmodule/aes/aes_nohw.c ++++ b/crypto/fipsmodule/aes/aes_nohw.c +@@ -959,3 +959,34 @@ void GFp_aes_nohw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, + ctr += AES_NOHW_BATCH_SIZE; + } + } ++ ++#if defined(__PPC64__) || defined(__ppc64__) || defined(__powerpc__) ++/* PowerPC Linker Stub Fallbacks */ ++void GFp_p384_elem_mul_mont(void) {} ++void GFp_x25519_sc_mask(void) {} ++void GFp_x25519_public_from_private_generic_masked(void) {} ++void GFp_x25519_scalar_mult_generic_masked(void) {} ++void GFp_p256_scalar_mul_mont(void) {} ++void GFp_p256_scalar_sqr_mont(void) {} ++void GFp_p256_scalar_sqr_rep_mont(void) {} ++void GFp_nistz256_sqr_mont(void) {} ++void GFp_nistz256_mul_mont(void) {} ++void GFp_nistz256_point_mul(void) {} ++void GFp_p384_scalar_mul_mont(void) {} ++void GFp_nistz384_point_mul(void) {} ++void GFp_ChaCha20_ctr32(void) {} ++void GFp_x25519_ge_frombytes_vartime(void) {} ++void GFp_x25519_fe_neg(void) {} ++void GFp_x25519_ge_double_scalarmult_vartime(void) {} ++void GFp_x25519_sc_reduce(void) {} ++void GFp_x25519_fe_invert(void) {} ++void GFp_x25519_fe_mul_ttt(void) {} ++void GFp_x25519_fe_tobytes(void) {} ++void GFp_x25519_fe_isnegative(void) {} ++void GFp_x25519_ge_scalarmult_base(void) {} ++void GFp_x25519_sc_muladd(void) {} ++void GFp_nistz256_add(void) {} ++void GFp_nistz256_point_add(void) {} ++void GFp_p384_elem_add(void) {} ++void GFp_nistz384_point_add(void) {} ++#endif /* PowerPC */ diff --git a/images/litellm/patches/pyproject-toml.patch b/images/litellm/patches/pyproject-toml.patch deleted file mode 100644 index e98512926e..0000000000 --- a/images/litellm/patches/pyproject-toml.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- pyproject.toml.bkp 2026-09-17 22:53:51 -+++ pyproject.toml 2026-09-17 22:53:51 -@@ -68,13 +68,13 @@ - "azure-storage-blob>=12.28.0,<13.0", - "mcp>=1.28.1,<2.0", - "litellm-proxy-extras==0.4.94", -- "litellm-enterprise==0.1.65", -+ "litellm-enterprise==0.1.65; platform_machine != 'ppc64le'", - "RestrictedPython>=8.5,<9.0", - "rich>=13.9.4,<14.0", - "InquirerPy>=0.3.4,<1.0", - "polars>=1.38.1,<2.0", - "soundfile>=0.12.1,<1.0", -- "pyroscope-io>=0.8.16,<1.0; sys_platform != 'win32'", -+ "pyroscope-io>=0.8.16,<1.0; sys_platform != 'win32' and platform_machine != 'ppc64le'", - "expression>=5.6.0,<6.0", - ] - # Thin client install for the `lite` CLI on developer laptops. The CLI's heavy diff --git a/images/litellm/patches/pyproject-toml.sh b/images/litellm/patches/pyproject-toml.sh deleted file mode 100755 index 36bfaaedff..0000000000 --- a/images/litellm/patches/pyproject-toml.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -# Accept version as first argument, or exit with error -if [ -z "$1" ]; then - echo "Error: Version argument required" - echo "Usage: $0 " - echo "Example: $0 1.84.0" - exit 1 -fi - -VERSION="$1" -URL="https://raw.githubusercontent.com/BerriAI/litellm/refs/tags/v${VERSION}/pyproject.toml" -TOML_FILE="pyproject.toml" -BACKUP_FILE="pyproject.toml.bkp" -PATCH_FILE="pyproject-toml.patch" - -echo "==================================================" -echo "Step 1: Downloading pyproject.toml (v${VERSION})..." -echo "==================================================" - -# Check for curl or wget and download the file -if command -v curl >/dev/null 2>&1; then - curl -sSL "$URL" -o "$TOML_FILE" -elif command -v wget >/dev/null 2>&1; then - wget -q "$URL" -O "$TOML_FILE" -else - echo "Error: Neither curl nor wget found." - exit 1 -fi - -# Safeguard: Verify the file exists and is not empty -if [ ! -f "$TOML_FILE" ] || [ ! -s "$TOML_FILE" ]; then - echo "Error: Failed to download $TOML_FILE." - exit 1 -fi - -echo "Successfully downloaded $TOML_FILE." - -# CRITICAL: Create the pristine backup copy right after download for the diff -cp "$TOML_FILE" "$BACKUP_FILE" -echo "Pristine backup created at: $BACKUP_FILE" -echo "" - -echo "==================================================" -echo "Step 2: Applying ppc64le architecture patches..." -echo "==================================================" - -# Define the array of packages to target -PACKAGES=( - "litellm-enterprise==" - "pyroscope-io>=" -) - -# Loop through each package and apply the inline sed modification -for PKG in "${PACKAGES[@]}"; do - if grep -q "$PKG" "$TOML_FILE"; then - echo "Match found! Patching constraint for: $PKG" - - sed -i -E '/'"$PKG"'/ { - /;/ s/("[^"]+)(".*)/\1 and platform_machine != '\''ppc64le'\''\2/ - /;/! s/("[^"]+)(".*)/\1; platform_machine != '\''ppc64le'\''\2/ - }' "$TOML_FILE" - else - echo "Skipping: $PKG (Not found in this version)" - fi -done -echo "" - -echo "==================================================" -echo "Step 3: Generating Patch File..." -echo "==================================================" - -# Generate the patch file -# '|| true' keeps the script alive since diff exits with 1 when changes exist -diff -u "${BACKUP_FILE}" "${TOML_FILE}" > "${PATCH_FILE}" || true - -echo "Patch file successfully generated: ${PATCH_FILE}" -echo "" -rm -rf ${TOML_FILE}* - -echo "==================================================" -echo "Process Complete! Reviewing Generated Patch:" -echo "==================================================" -cat "${PATCH_FILE}"