mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
chore: move workspace packages under litellm (#51000)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
f6bee81c73
commit
db6dfb6bb6
2043 changed files with 763 additions and 271 deletions
|
|
@ -26,7 +26,7 @@ metadata:
|
|||
- Keep query execution inside the repository, with one implementation per repository and no backend switch or fallback
|
||||
- A repository is either all Prisma or all native, never a mix of both
|
||||
- Prisma is fine for the implementation, adding a query does not require a Rust port
|
||||
- Native Rust callers use `litellm-rust/crates/db` directly
|
||||
- Native Rust callers use `litellm/rust/crates/db` directly
|
||||
|
||||
## Framework wiring
|
||||
|
||||
|
|
|
|||
|
|
@ -81,11 +81,11 @@ Use this only when a port is explicitly requested. Repository extraction does no
|
|||
|
||||
- Identify the repository's inputs, outputs, errors and transaction boundary
|
||||
- List repositories that share a transaction with it, they move together
|
||||
- Check `litellm-rust/crates/db` for an equivalent query and reuse it when its behavior matches
|
||||
- Check `litellm/rust/crates/db` for an equivalent query and reuse it when its behavior matches
|
||||
|
||||
### Steps
|
||||
|
||||
1. Rust queries, following `litellm-rust/crates/db/AGENTS.md`
|
||||
1. Rust queries, following `litellm/rust/crates/db/AGENTS.md`
|
||||
- Static SQL in `queries/`, compile-checked with SQLx, typed inputs and row projections in `src/`
|
||||
- Dynamic filters and sort keys become closed Rust enums that select static SQL, every value is bound
|
||||
- Refresh SQLx query metadata after SQL changes
|
||||
|
|
|
|||
10
.github/actions/cache-cargo-build/action.yml
vendored
10
.github/actions/cache-cargo-build/action.yml
vendored
|
|
@ -3,7 +3,7 @@ description: >-
|
|||
Cache the Cargo registry and target directory the root package's build needs,
|
||||
so only the first job on a given Cargo.lock compiles the bridge from scratch.
|
||||
|
||||
litellm builds through maturin, which compiles litellm-rust/crates/python-bridge
|
||||
litellm builds through maturin, which compiles litellm/rust/crates/python-bridge
|
||||
in the dev profile for editable installs. `uv sync` therefore pays a full build
|
||||
in every job that installs the workspace. Nothing caught it, because the uv cache
|
||||
holds wheels uv downloads rather than wheels it builds, and a path dependency
|
||||
|
|
@ -31,8 +31,8 @@ runs:
|
|||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
litellm-rust/target
|
||||
key: ${{ runner.os }}-maturin-${{ inputs.profile }}-${{ hashFiles('litellm-rust/Cargo.lock') }}
|
||||
litellm/rust/target
|
||||
key: ${{ runner.os }}-maturin-${{ inputs.profile }}-${{ hashFiles('litellm/rust/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maturin-${{ inputs.profile }}-
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ runs:
|
|||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
litellm-rust/target
|
||||
key: ${{ runner.os }}-maturin-${{ inputs.profile }}-${{ hashFiles('litellm-rust/Cargo.lock') }}
|
||||
litellm/rust/target
|
||||
key: ${{ runner.os }}-maturin-${{ inputs.profile }}-${{ hashFiles('litellm/rust/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maturin-${{ inputs.profile }}-
|
||||
|
|
|
|||
2
.github/ci-coverage-allowlist.yml
vendored
2
.github/ci-coverage-allowlist.yml
vendored
|
|
@ -73,4 +73,4 @@ dockerfiles:
|
|||
clippy, and compile jobs already cover the code it packages. Revisit when the gateway is
|
||||
published
|
||||
paths:
|
||||
- litellm-rust/crates/gateway/Dockerfile
|
||||
- litellm/rust/crates/gateway/Dockerfile
|
||||
|
|
|
|||
4
.github/codecov.yml
vendored
4
.github/codecov.yml
vendored
|
|
@ -4,7 +4,7 @@ codecov:
|
|||
wait_for_ci: false # post as soon as expected uploads arrive, don't wait on CI
|
||||
|
||||
ignore:
|
||||
- "litellm-rust/**"
|
||||
- "litellm/rust/**"
|
||||
|
||||
# Flagged uploads avoid overlapping sessions on reruns.
|
||||
# Only the flags below reuse parent coverage, avoiding stale line maps elsewhere.
|
||||
|
|
@ -40,7 +40,7 @@ component_management:
|
|||
- "*/proxy/auth/**"
|
||||
- component_id: "Enterprise"
|
||||
paths:
|
||||
- "enterprise/**"
|
||||
- "litellm/enterprise/**"
|
||||
- component_id: "Batches"
|
||||
paths:
|
||||
- "*/proxy/batches_endpoints/**"
|
||||
|
|
|
|||
49
.github/packaging/build_backend.py
vendored
Normal file
49
.github/packaging/build_backend.py
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import sys
|
||||
from collections.abc import Mapping
|
||||
from pathlib import Path
|
||||
from typing import Final
|
||||
|
||||
import maturin
|
||||
from cli_package import PACKAGE_DIR, map_wheel
|
||||
from maturin import (
|
||||
build_sdist as build_sdist,
|
||||
)
|
||||
from maturin import (
|
||||
get_requires_for_build_editable as get_requires_for_build_editable,
|
||||
)
|
||||
from maturin import (
|
||||
get_requires_for_build_sdist as get_requires_for_build_sdist,
|
||||
)
|
||||
from maturin import (
|
||||
get_requires_for_build_wheel as get_requires_for_build_wheel,
|
||||
)
|
||||
from maturin import (
|
||||
prepare_metadata_for_build_editable as prepare_metadata_for_build_editable,
|
||||
)
|
||||
from maturin import (
|
||||
prepare_metadata_for_build_wheel as prepare_metadata_for_build_wheel,
|
||||
)
|
||||
|
||||
|
||||
def build_wheel(
|
||||
wheel_directory: str,
|
||||
config_settings: Mapping[str, str | list[str]] | None = None,
|
||||
metadata_directory: str | None = None,
|
||||
) -> str:
|
||||
filename: Final = maturin.build_wheel(wheel_directory, config_settings, metadata_directory)
|
||||
map_wheel(Path(wheel_directory) / filename)
|
||||
return filename
|
||||
|
||||
|
||||
def build_editable(
|
||||
wheel_directory: str,
|
||||
config_settings: Mapping[str, str | list[str]] | None = None,
|
||||
metadata_directory: str | None = None,
|
||||
) -> str:
|
||||
filename: Final = maturin.build_editable(wheel_directory, config_settings, metadata_directory)
|
||||
map_wheel(Path(wheel_directory) / filename, source=Path(__file__).resolve().parents[2] / PACKAGE_DIR)
|
||||
return filename
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
build_editable(sys.argv[1])
|
||||
93
.github/packaging/cli_package.py
vendored
Normal file
93
.github/packaging/cli_package.py
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import argparse
|
||||
import base64
|
||||
import copy
|
||||
import csv
|
||||
import hashlib
|
||||
import io
|
||||
import os
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import Final
|
||||
from zipfile import ZipFile, ZipInfo
|
||||
|
||||
PACKAGE_DIR: Final = "litellm/cli"
|
||||
PACKAGE_NAME: Final = "litellm_cli"
|
||||
|
||||
|
||||
def editable_support(source: Path) -> tuple[tuple[str, bytes], ...]:
|
||||
module: Final = "_litellm_cli_editable"
|
||||
finder: Final = (
|
||||
"import importlib.util\nimport sys\n\n"
|
||||
"class _Finder:\n"
|
||||
" @staticmethod\n"
|
||||
" def find_spec(fullname, path=None, target=None):\n"
|
||||
f" if fullname == {PACKAGE_NAME!r}:\n"
|
||||
" return importlib.util.spec_from_file_location(\n"
|
||||
f" fullname, {str(source / '__init__.py')!r},\n"
|
||||
f" submodule_search_locations=[{str(source)!r}])\n"
|
||||
" return None\n\n"
|
||||
"sys.meta_path.insert(0, _Finder())\n"
|
||||
)
|
||||
return ((f"{module}.py", finder.encode()), (f"{module}.pth", f"import {module}\n".encode()))
|
||||
|
||||
|
||||
def _name(name: str) -> str:
|
||||
prefix: Final = f"{PACKAGE_DIR}/"
|
||||
return f"{PACKAGE_NAME}/{name.removeprefix(prefix)}" if name.startswith(prefix) else name
|
||||
|
||||
|
||||
def _info(original: ZipInfo) -> ZipInfo:
|
||||
mapped: Final = copy.copy(original)
|
||||
mapped.filename = _name(original.filename)
|
||||
return mapped
|
||||
|
||||
|
||||
def _record(entries: tuple[tuple[ZipInfo, bytes], ...], record: str) -> bytes:
|
||||
buffer: Final = io.StringIO(newline="")
|
||||
writer: Final = csv.writer(buffer, lineterminator="\n")
|
||||
writer.writerows(
|
||||
(
|
||||
info.filename,
|
||||
"sha256=" + base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode(),
|
||||
str(len(data)),
|
||||
)
|
||||
for info, data in entries
|
||||
)
|
||||
writer.writerow((record, "", ""))
|
||||
return buffer.getvalue().encode()
|
||||
|
||||
|
||||
def map_wheel(wheel: Path, *, source: Path | None = None) -> None:
|
||||
with ZipFile(wheel) as archive:
|
||||
records: Final = tuple(info for info in archive.infolist() if info.filename.endswith(".dist-info/RECORD"))
|
||||
if len(records) != 1:
|
||||
raise ValueError("A wheel must contain exactly one RECORD")
|
||||
entries: Final = tuple(
|
||||
(_info(info), archive.read(info))
|
||||
for info in archive.infolist()
|
||||
if info != records[0] and (source is None or not info.filename.startswith(f"{PACKAGE_DIR}/"))
|
||||
)
|
||||
additions: Final = () if source is None else tuple((ZipInfo(name), data) for name, data in editable_support(source))
|
||||
contents: Final = (*entries, *additions)
|
||||
names: Final = tuple(info.filename for info, _ in contents)
|
||||
if len(names) != len(frozenset(names)):
|
||||
raise ValueError("The CLI package mapping would overwrite a wheel member")
|
||||
if source is None and not any(name.startswith(f"{PACKAGE_NAME}/") for name in names):
|
||||
raise ValueError("The wheel does not contain the CLI package")
|
||||
with NamedTemporaryFile(dir=wheel.parent, suffix=".whl", delete=False) as temporary:
|
||||
destination: Final = Path(temporary.name)
|
||||
try:
|
||||
with ZipFile(destination, "w") as archive:
|
||||
for info, data in contents:
|
||||
archive.writestr(info, data)
|
||||
archive.writestr(records[0], _record(contents, records[0].filename))
|
||||
os.replace(destination, wheel)
|
||||
finally:
|
||||
destination.unlink(missing_ok=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser: Final = argparse.ArgumentParser()
|
||||
parser.add_argument("wheels", nargs="+", type=Path)
|
||||
for wheel in parser.parse_args().wheels:
|
||||
map_wheel(wheel)
|
||||
4
.github/scripts/ci/classify_changes.sh
vendored
4
.github/scripts/ci/classify_changes.sh
vendored
|
|
@ -19,11 +19,11 @@ while IFS= read -r file || [ -n "$file" ]; do
|
|||
esac
|
||||
case "$file" in
|
||||
*.md | *.mdx) : ;;
|
||||
pyproject.toml | */pyproject.toml | uv.lock | uv.toml | .python-version | rust-toolchain.toml | litellm-rust/* | litellm/__init__.py | litellm/proxy/proxy_server.py | litellm/*mcp* | tests/*mcp* | litellm/integrations/arize/* | tests/base_sdk_tests/* | scripts/check_mcp_sdk_install.py | .github/workflows/test-mcp-dependency-resolution.yml | .github/actions/detect-changes/* | .github/actions/setup-uv-with-retries/* | .github/actions/cache-cargo-build/* | .github/scripts/detect_changes.sh | .github/scripts/uv_sync_with_retries.sh | .github/scripts/ci/classify_changes.sh | tests/unit/test_ci_path_filter.py | tests/unit/test_detect_changes.py)
|
||||
pyproject.toml | */pyproject.toml | uv.lock | uv.toml | .python-version | rust-toolchain.toml | litellm/rust/* | litellm/__init__.py | litellm/proxy/proxy_server.py | litellm/*mcp* | tests/*mcp* | litellm/integrations/arize/* | tests/base_sdk_tests/* | scripts/check_mcp_sdk_install.py | .github/workflows/test-mcp-dependency-resolution.yml | .github/actions/detect-changes/* | .github/actions/setup-uv-with-retries/* | .github/actions/cache-cargo-build/* | .github/scripts/detect_changes.sh | .github/scripts/uv_sync_with_retries.sh | .github/scripts/ci/classify_changes.sh | tests/unit/test_ci_path_filter.py | tests/unit/test_detect_changes.py)
|
||||
has_mcp_dependencies=true ;;
|
||||
esac
|
||||
case "$file" in
|
||||
litellm-rust/* | litellm/rust_bridge/* | rust-toolchain.toml | pyproject.toml | uv.lock | tests/windows_tests/* | .github/scripts/ci/* | .github/actions/*)
|
||||
litellm/rust/* | litellm/rust_bridge/* | rust-toolchain.toml | pyproject.toml | uv.lock | tests/windows_tests/* | .github/scripts/ci/* | .github/actions/*)
|
||||
has_windows_release=true ;;
|
||||
esac
|
||||
case "$file" in
|
||||
|
|
|
|||
12
.github/scripts/verify_linux_native_wheel.py
vendored
12
.github/scripts/verify_linux_native_wheel.py
vendored
|
|
@ -128,7 +128,17 @@ def main(
|
|||
member.filename
|
||||
for member in wheel_members
|
||||
if member.filename.endswith((".pdb", ".dwp", ".rlib", ".rmeta", "Cargo.toml", "Cargo.lock"))
|
||||
or member.filename.startswith(("litellm/deploy/", "litellm/ui/", "litellm/vscode-extension/"))
|
||||
or member.filename.startswith(
|
||||
(
|
||||
"litellm/deploy/",
|
||||
"litellm/ui/",
|
||||
"litellm/vscode-extension/",
|
||||
"litellm/enterprise/",
|
||||
"litellm/proxy-extras/",
|
||||
"litellm/rust/",
|
||||
"litellm/packaging/",
|
||||
)
|
||||
)
|
||||
or any(part.endswith(".dSYM") for part in PurePosixPath(member.filename).parts)
|
||||
)
|
||||
native_member: Final = native_members[0]
|
||||
|
|
|
|||
10
.github/workflows/check-schema-sync.yml
vendored
10
.github/workflows/check-schema-sync.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
paths:
|
||||
- 'schema.prisma'
|
||||
- 'litellm/proxy/schema.prisma'
|
||||
- 'litellm-proxy-extras/litellm_proxy_extras/schema.prisma'
|
||||
- 'litellm/proxy-extras/litellm_proxy_extras/schema.prisma'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
- name: Reject symlinked schema files
|
||||
run: |
|
||||
for f in schema.prisma litellm/proxy/schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma; do
|
||||
for f in schema.prisma litellm/proxy/schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma; do
|
||||
if [ -L "$f" ]; then
|
||||
echo "::error file=$f::$f is a symlink, which is not allowed"
|
||||
exit 1
|
||||
|
|
@ -43,8 +43,8 @@ jobs:
|
|||
EXIT=1
|
||||
}
|
||||
|
||||
diff schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma || {
|
||||
echo "::error file=litellm-proxy-extras/litellm_proxy_extras/schema.prisma::litellm-proxy-extras/litellm_proxy_extras/schema.prisma differs from root schema.prisma"
|
||||
diff schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma || {
|
||||
echo "::error file=litellm/proxy-extras/litellm_proxy_extras/schema.prisma::litellm/proxy-extras/litellm_proxy_extras/schema.prisma differs from root schema.prisma"
|
||||
EXIT=1
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ jobs:
|
|||
echo ""
|
||||
echo "To fix, run from the repo root:"
|
||||
echo " cp schema.prisma litellm/proxy/schema.prisma"
|
||||
echo " cp schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma"
|
||||
echo " cp schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
2
.github/workflows/cost-map-guard.yml
vendored
2
.github/workflows/cost-map-guard.yml
vendored
|
|
@ -74,5 +74,5 @@ jobs:
|
|||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
git show "${HEAD_SHA}:model_prices_and_context_window.json" > "$RUNNER_TEMP/model_prices_and_context_window.json"
|
||||
cargo run --locked --quiet --manifest-path litellm-rust/Cargo.toml -p litellm-model-catalog --bin check-registry \
|
||||
cargo run --locked --quiet --manifest-path litellm/rust/Cargo.toml -p litellm-model-catalog --bin check-registry \
|
||||
-- "$RUNNER_TEMP/model_prices_and_context_window.json"
|
||||
|
|
|
|||
12
.github/workflows/guard-fork-dependencies.yml
vendored
12
.github/workflows/guard-fork-dependencies.yml
vendored
|
|
@ -8,8 +8,8 @@ on:
|
|||
paths:
|
||||
- "uv.lock"
|
||||
- "pyproject.toml"
|
||||
- "litellm-proxy-extras/pyproject.toml"
|
||||
- "enterprise/pyproject.toml"
|
||||
- "litellm/proxy-extras/pyproject.toml"
|
||||
- "litellm/enterprise/pyproject.toml"
|
||||
|
||||
permissions: {}
|
||||
|
||||
|
|
@ -130,8 +130,12 @@ jobs:
|
|||
}
|
||||
|
||||
check_deps base/pyproject.toml pr/pyproject.toml "pyproject.toml" || had_error=1
|
||||
check_deps base/litellm-proxy-extras/pyproject.toml pr/litellm-proxy-extras/pyproject.toml "litellm-proxy-extras/pyproject.toml" || had_error=1
|
||||
check_deps base/enterprise/pyproject.toml pr/enterprise/pyproject.toml "enterprise/pyproject.toml" || had_error=1
|
||||
base_extras=base/litellm/proxy-extras/pyproject.toml
|
||||
[ -f "$base_extras" ] || base_extras=base/litellm-proxy-extras/pyproject.toml
|
||||
base_enterprise=base/litellm/enterprise/pyproject.toml
|
||||
[ -f "$base_enterprise" ] || base_enterprise=base/enterprise/pyproject.toml
|
||||
check_deps "$base_extras" pr/litellm/proxy-extras/pyproject.toml "litellm/proxy-extras/pyproject.toml" || had_error=1
|
||||
check_deps "$base_enterprise" pr/litellm/enterprise/pyproject.toml "litellm/enterprise/pyproject.toml" || had_error=1
|
||||
|
||||
if [ "$had_error" -ne 0 ]; then
|
||||
echo ""
|
||||
|
|
|
|||
6
.github/workflows/image-scan.yml
vendored
6
.github/workflows/image-scan.yml
vendored
|
|
@ -14,16 +14,16 @@ on:
|
|||
- gateway/main.py
|
||||
- gateway/launch.py
|
||||
- gateway/routes/allowlist.py
|
||||
- litellm_cli/**
|
||||
- litellm/cli/**
|
||||
- backend/main.py
|
||||
- backend/routes/allowlist.py
|
||||
- litellm-rust/**
|
||||
- litellm/rust/**
|
||||
- litellm/proxy/lens/**
|
||||
- litellm/proxy/prisma_migration.py
|
||||
- litellm/proxy/admin_mcp.py
|
||||
- litellm/proxy/proxy_server.py
|
||||
- pyproject.toml
|
||||
- litellm-proxy-extras/**
|
||||
- litellm/proxy-extras/**
|
||||
- tests/integration/database/image/**
|
||||
- uv.lock
|
||||
- litellm/ui/litellm-dashboard/package-lock.json
|
||||
|
|
|
|||
8
.github/workflows/sync-schema.yml
vendored
8
.github/workflows/sync-schema.yml
vendored
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
|
||||
- name: Reject symlinked schema files
|
||||
run: |
|
||||
for f in schema.prisma litellm/proxy/schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma; do
|
||||
for f in schema.prisma litellm/proxy/schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma; do
|
||||
if [ -L "$f" ]; then
|
||||
echo "::error file=$f::$f is a symlink, which is not allowed"
|
||||
exit 1
|
||||
|
|
@ -47,12 +47,12 @@ jobs:
|
|||
- name: Copy root schema to other locations
|
||||
run: |
|
||||
cp schema.prisma litellm/proxy/schema.prisma
|
||||
cp schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
cp schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
|
||||
- name: Check for changes
|
||||
id: diff
|
||||
run: |
|
||||
if git diff --quiet -- litellm/proxy/schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma; then
|
||||
if git diff --quiet -- litellm/proxy/schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma; then
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Schemas already in sync. Nothing to do."
|
||||
else
|
||||
|
|
@ -68,6 +68,6 @@ jobs:
|
|||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git checkout -B "$GITHUB_HEAD_REF"
|
||||
git add -- litellm/proxy/schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
git add -- litellm/proxy/schema.prisma litellm/proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
git commit -m "chore: sync schema.prisma copies from root"
|
||||
git push origin "HEAD:$GITHUB_HEAD_REF"
|
||||
|
|
|
|||
4
.github/workflows/test-linting.yml
vendored
4
.github/workflows/test-linting.yml
vendored
|
|
@ -114,7 +114,7 @@ jobs:
|
|||
- name: Check ruff format
|
||||
if: steps.changes.outputs.decision != 'skip'
|
||||
run: |
|
||||
git diff --name-only --diff-filter=ACMR "$GATE_BASE_SHA" HEAD -- ':(glob)litellm/**/*.py' | grep -Ev '^litellm/(enterprise|ui|vscode-extension)/' > "$RUNNER_TEMP/ruff_format_files.txt" || true
|
||||
git diff --name-only --diff-filter=ACMR "$GATE_BASE_SHA" HEAD -- ':(glob)litellm/**/*.py' | grep -Ev '^litellm/(enterprise|ui|vscode-extension|rust|proxy-extras|packaging|cli)/' > "$RUNNER_TEMP/ruff_format_files.txt" || true
|
||||
if [ ! -s "$RUNNER_TEMP/ruff_format_files.txt" ]; then
|
||||
echo "No changed litellm Python files to check with ruff format."
|
||||
exit 0
|
||||
|
|
@ -375,7 +375,7 @@ jobs:
|
|||
exit 0
|
||||
fi
|
||||
files="$(git diff --name-only "$base" HEAD)"
|
||||
if grep -Ev '^litellm/(ui|vscode-extension)/' <<< "$files" | grep -E '^(litellm/|enterprise/|(pyproject\.toml|uv\.lock)$|\.github/workflows/test-linting\.yml$)' >/dev/null || grep -Eq '^litellm/ui/litellm-dashboard/(src/lib/http/schema\.d\.ts|scripts/gen-api-types\.mjs|package(-lock)?\.json)$' <<< "$files"; then
|
||||
if grep -Ev '^litellm/(ui|vscode-extension|rust|proxy-extras|packaging|cli)/' <<< "$files" | grep -E '^(litellm/|enterprise/|(pyproject\.toml|uv\.lock)$|\.github/workflows/test-linting\.yml$)' >/dev/null || grep -Eq '^litellm/ui/litellm-dashboard/(src/lib/http/schema\.d\.ts|scripts/gen-api-types\.mjs|package(-lock)?\.json)$' <<< "$files"; then
|
||||
echo "relevant=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "No litellm, enterprise, dependency or generator changes in this pull request, nothing to verify."
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ on:
|
|||
- "uv.toml"
|
||||
- ".python-version"
|
||||
- "rust-toolchain.toml"
|
||||
- "litellm-rust/**"
|
||||
- "litellm/rust/**"
|
||||
- "litellm/__init__.py"
|
||||
- "litellm/_version.py"
|
||||
- "litellm/_lazy_imports_registry.py"
|
||||
|
|
|
|||
28
.github/workflows/test-rust-db.yml
vendored
28
.github/workflows/test-rust-db.yml
vendored
|
|
@ -3,11 +3,11 @@ name: LiteLLM Rust DB
|
|||
on:
|
||||
push:
|
||||
paths:
|
||||
- "litellm-rust/crates/db/**"
|
||||
- "litellm-rust/Cargo.toml"
|
||||
- "litellm-rust/Cargo.lock"
|
||||
- "litellm-rust/clippy.toml"
|
||||
- "litellm-proxy-extras/litellm_proxy_extras/migrations/**"
|
||||
- "litellm/rust/crates/db/**"
|
||||
- "litellm/rust/Cargo.toml"
|
||||
- "litellm/rust/Cargo.lock"
|
||||
- "litellm/rust/clippy.toml"
|
||||
- "litellm/proxy-extras/litellm_proxy_extras/migrations/**"
|
||||
- "**/schema.prisma"
|
||||
- ".cargo/**"
|
||||
- "rust-toolchain.toml"
|
||||
|
|
@ -20,11 +20,11 @@ on:
|
|||
- main
|
||||
- "litellm_**"
|
||||
paths:
|
||||
- "litellm-rust/crates/db/**"
|
||||
- "litellm-rust/Cargo.toml"
|
||||
- "litellm-rust/Cargo.lock"
|
||||
- "litellm-rust/clippy.toml"
|
||||
- "litellm-proxy-extras/litellm_proxy_extras/migrations/**"
|
||||
- "litellm/rust/crates/db/**"
|
||||
- "litellm/rust/Cargo.toml"
|
||||
- "litellm/rust/Cargo.lock"
|
||||
- "litellm/rust/clippy.toml"
|
||||
- "litellm/proxy-extras/litellm_proxy_extras/migrations/**"
|
||||
- "**/schema.prisma"
|
||||
- ".cargo/**"
|
||||
- "rust-toolchain.toml"
|
||||
|
|
@ -71,7 +71,7 @@ jobs:
|
|||
SQLX_OFFLINE: "false"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: litellm-rust
|
||||
working-directory: litellm/rust
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
|
|
@ -89,7 +89,7 @@ jobs:
|
|||
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
workspaces: litellm-rust
|
||||
workspaces: litellm/rust
|
||||
cache-on-failure: true
|
||||
|
||||
- name: Set up sccache
|
||||
|
|
@ -103,13 +103,13 @@ jobs:
|
|||
|
||||
- name: Deploy Prisma migrations
|
||||
working-directory: .
|
||||
run: uv run --no-sync prisma migrate deploy --schema litellm-proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
run: uv run --no-sync prisma migrate deploy --schema litellm/proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
|
||||
- name: Install SQLx CLI
|
||||
run: cargo install sqlx-cli --version 0.9.0 --locked --no-default-features -F postgres
|
||||
|
||||
- name: Check SQLx query metadata
|
||||
working-directory: litellm-rust/crates/db
|
||||
working-directory: litellm/rust/crates/db
|
||||
run: cargo sqlx prepare --check
|
||||
|
||||
- name: Test database queries
|
||||
|
|
|
|||
14
.github/workflows/test-rust.yml
vendored
14
.github/workflows/test-rust.yml
vendored
|
|
@ -3,7 +3,7 @@ name: LiteLLM Rust
|
|||
on:
|
||||
push:
|
||||
paths:
|
||||
- "litellm-rust/**"
|
||||
- "litellm/rust/**"
|
||||
- "model_prices_and_context_window.json"
|
||||
- "litellm/rust_bridge/**"
|
||||
- "scripts/generate_trace_types.py"
|
||||
|
|
@ -38,7 +38,7 @@ on:
|
|||
- main
|
||||
- "litellm_**"
|
||||
paths:
|
||||
- "litellm-rust/**"
|
||||
- "litellm/rust/**"
|
||||
- "model_prices_and_context_window.json"
|
||||
- "litellm/rust_bridge/**"
|
||||
- "scripts/generate_trace_types.py"
|
||||
|
|
@ -90,7 +90,7 @@ jobs:
|
|||
timeout-minutes: 15
|
||||
defaults:
|
||||
run:
|
||||
working-directory: litellm-rust
|
||||
working-directory: litellm/rust
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
|
|
@ -102,7 +102,7 @@ jobs:
|
|||
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
workspaces: litellm-rust
|
||||
workspaces: litellm/rust
|
||||
cache-on-failure: true
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ jobs:
|
|||
CARGO_PROFILE_DEV_DEBUG: line-tables-only
|
||||
defaults:
|
||||
run:
|
||||
working-directory: litellm-rust
|
||||
working-directory: litellm/rust
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
|
|
@ -149,7 +149,7 @@ jobs:
|
|||
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
workspaces: litellm-rust
|
||||
workspaces: litellm/rust
|
||||
cache-on-failure: true
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ jobs:
|
|||
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
workspaces: litellm-rust
|
||||
workspaces: litellm/rust
|
||||
cache-on-failure: true
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ on:
|
|||
paths:
|
||||
- "litellm/deploy/terraform/provider/**"
|
||||
- "litellm/proxy/**"
|
||||
- "enterprise/**"
|
||||
- "litellm/enterprise/**"
|
||||
- ".github/workflows/test-terraform-provider.yml"
|
||||
|
||||
permissions:
|
||||
|
|
|
|||
10
.github/workflows/test-unit.yml
vendored
10
.github/workflows/test-unit.yml
vendored
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
id: rust-bridge-key
|
||||
if: steps.changes.outputs.decision != 'skip'
|
||||
env:
|
||||
RUST_BRIDGE_CACHE_KEY: ${{ runner.os }}-rust-bridge-editable-${{ hashFiles('litellm-rust/Cargo.lock', 'litellm-rust/Cargo.toml', 'litellm-rust/crates/**', 'model_prices_and_context_window.json', 'pyproject.toml', 'packaging/litellm-proxy/pyproject.toml') }}
|
||||
RUST_BRIDGE_CACHE_KEY: ${{ runner.os }}-rust-bridge-editable-${{ hashFiles('litellm/rust/Cargo.lock', 'litellm/rust/Cargo.toml', 'litellm/rust/crates/**', 'model_prices_and_context_window.json', 'pyproject.toml', 'litellm/packaging/litellm-proxy/pyproject.toml') }}
|
||||
run: echo "key=$RUST_BRIDGE_CACHE_KEY" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Python
|
||||
|
|
@ -93,7 +93,7 @@ jobs:
|
|||
CARGO_INCREMENTAL: "0"
|
||||
run: |
|
||||
mkdir -p rust-bridge-dist
|
||||
uv run --no-project --with maturin==1.15.0 python -c 'import maturin; maturin.build_editable("rust-bridge-dist")'
|
||||
uv run --no-project --with maturin==1.15.0 python .github/packaging/build_backend.py rust-bridge-dist
|
||||
strip --strip-debug litellm/rust_bridge/_native.abi3.so
|
||||
mkdir -p rust-bridge-dist/litellm/rust_bridge
|
||||
cp litellm/rust_bridge/_native.abi3.so rust-bridge-dist/litellm/rust_bridge/_native.abi3.so
|
||||
|
|
@ -101,14 +101,14 @@ jobs:
|
|||
- name: Build the gateway wheel once for test shards
|
||||
if: steps.changes.outputs.decision != 'skip' && steps.rust-bridge-cache.outputs.cache-hit != 'true'
|
||||
timeout-minutes: 15
|
||||
working-directory: packaging/litellm-proxy
|
||||
working-directory: litellm/packaging/litellm-proxy
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
SCCACHE_GHA_VERSION: litellm-ci-v1
|
||||
SCCACHE_GHA_RW_MODE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'READ_WRITE' || 'READ_ONLY' }}
|
||||
CARGO_INCREMENTAL: "0"
|
||||
run: uv run --no-project --with maturin==1.15.0 maturin build --profile dev --strip --out ../../rust-bridge-dist
|
||||
run: uv run --no-project --with maturin==1.15.0 maturin build --profile dev --strip --out ../../../rust-bridge-dist
|
||||
|
||||
- name: Upload Rust bridge artifact
|
||||
if: steps.changes.outputs.decision != 'skip'
|
||||
|
|
@ -1158,7 +1158,7 @@ jobs:
|
|||
--timeout="${TEST_TIMEOUT_SECONDS}" \
|
||||
--rerun-except "from pytest-timeout" \
|
||||
--durations=20 \
|
||||
--cov=./litellm --cov=./enterprise/litellm_enterprise \
|
||||
--cov=./litellm --cov=./litellm/enterprise/litellm_enterprise \
|
||||
--cov-report=xml:coverage.xml \
|
||||
--cov-config=pyproject.toml
|
||||
status=$?
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -18,7 +18,7 @@ __pycache__/
|
|||
# Rust bridge build artifacts (compiled, platform-specific; regenerated by maturin/cargo)
|
||||
litellm/rust_bridge/_native*.so
|
||||
litellm/rust_bridge/_native*.pyd
|
||||
litellm-rust/target/
|
||||
litellm/rust/target/
|
||||
|
||||
# Python package build output
|
||||
dist/
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
Portions of this software are licensed as follows:
|
||||
|
||||
* All content that resides under the "enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "enterprise/LICENSE".
|
||||
* All content that resides under the "litellm/enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "litellm/enterprise/LICENSE".
|
||||
* Content outside of the above mentioned directories or restrictions above is available under the MIT license as defined below.
|
||||
---
|
||||
MIT License
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -54,7 +54,7 @@ help:
|
|||
@echo " make test-integration - Run integration tests"
|
||||
@echo " make test-unit-helm - Run helm unit tests"
|
||||
@echo " make test-rust-extension - Build the Rust extension and run its public Python tests"
|
||||
@echo " make rust-sqlx-prepare - Refresh litellm-rust/crates/db/.sqlx against a migrated Postgres container"
|
||||
@echo " make rust-sqlx-prepare - Refresh litellm/rust/crates/db/.sqlx against a migrated Postgres container"
|
||||
@echo ""
|
||||
@echo "Heavy targets (check, lint) queue for LITELLM_GATE_SLOTS machine-wide"
|
||||
@echo "slots (default 2; 0 disables) so parallel sessions don't thrash one machine."
|
||||
|
|
@ -294,7 +294,7 @@ test-rust-extension:
|
|||
"$$temporary/venv/bin/python" -I -m pytest --import-mode=importlib -m requires_rust_extension tests/test_litellm_rust
|
||||
|
||||
rust-sqlx-prepare:
|
||||
cd litellm-rust && cargo run -p litellm-db-testing --bin sqlx-prepare
|
||||
cd litellm/rust && cargo run -p litellm-db-testing --bin sqlx-prepare
|
||||
|
||||
test: install-test-deps
|
||||
$(UV_RUN) pytest tests/
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ from typing import TYPE_CHECKING, Final
|
|||
from typing_extensions import assert_never
|
||||
from uvicorn.main import main as uvicorn_main
|
||||
|
||||
from litellm_cli.main import without_gc_pauses
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from litellm.proxy.db.db_url_settings import DatabaseURLSettings
|
||||
from litellm.proxy.db.pgbouncer import PgBouncerError, PgBouncerSettings
|
||||
|
|
@ -67,6 +65,8 @@ def pool_database_url(
|
|||
|
||||
|
||||
def worker_app() -> "ASGIApp":
|
||||
from litellm_cli.main import without_gc_pauses
|
||||
|
||||
with without_gc_pauses():
|
||||
from gateway.main import app
|
||||
from litellm.proxy.rust_forward.mode import rust_forward_mode
|
||||
|
|
|
|||
|
|
@ -689,7 +689,7 @@ class LevelRoutingStreamHandler(logging.StreamHandler):
|
|||
def _parse_env_flag(value: str | None) -> bool:
|
||||
"""Strict opt-in parse for a boolean env var such as JSON_LOGS: only "true" (any case) enables it.
|
||||
|
||||
Matches the reader in litellm-proxy-extras/_logging.py. The previous
|
||||
Matches the reader in litellm/proxy-extras/_logging.py. The previous
|
||||
bool(os.getenv(...)) treated any non-empty value, including "false" and "0",
|
||||
as enabled.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -74,9 +74,9 @@ ENV UV_PROJECT_ENVIRONMENT=/app/.venv \
|
|||
|
||||
# Copy dependency metadata first for layer caching
|
||||
COPY pyproject.toml uv.lock ./
|
||||
COPY enterprise/pyproject.toml enterprise/
|
||||
COPY litellm-proxy-extras/pyproject.toml litellm-proxy-extras/
|
||||
COPY packaging/litellm-proxy/pyproject.toml packaging/litellm-proxy/
|
||||
COPY litellm/enterprise/pyproject.toml litellm/enterprise/
|
||||
COPY litellm/proxy-extras/pyproject.toml litellm/proxy-extras/
|
||||
COPY litellm/packaging/litellm-proxy/pyproject.toml litellm/packaging/litellm-proxy/
|
||||
|
||||
# Install third-party dependencies (cached unless pyproject.toml/uv.lock change)
|
||||
RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-groups --no-editable \
|
||||
|
|
@ -116,6 +116,8 @@ RUN uv sync --frozen --no-install-package litellm-proxy --no-default-groups --no
|
|||
|
||||
RUN uv pip install --python /app/.venv/bin/python --no-deps /wheels/litellm_proxy-*.whl
|
||||
|
||||
RUN cp -r litellm/enterprise "$(.venv/bin/python -c 'import sysconfig; print(sysconfig.get_path("purelib"))')/litellm/enterprise"
|
||||
|
||||
RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \
|
||||
npm_config_cache=/root/.npm \
|
||||
prisma generate --schema=./schema.prisma
|
||||
|
|
@ -183,9 +185,7 @@ COPY --from=builder /app/schema.prisma /app/schema.prisma
|
|||
COPY --from=builder /app/litellm/proxy/prisma_migration.py /app/litellm/proxy/prisma_migration.py
|
||||
# enterprise/ is imported by source path at runtime (proxy_cli puts the
|
||||
# working directory on sys.path; litellm/proxy/hooks resolves
|
||||
# enterprise.enterprise_hooks from it)
|
||||
COPY --from=builder /app/enterprise /app/enterprise
|
||||
COPY --from=builder /app/litellm-proxy-extras /app/litellm-proxy-extras
|
||||
# litellm.enterprise.enterprise_hooks from it)
|
||||
COPY --from=builder /app/gateway /app/gateway
|
||||
COPY --from=builder /app/backend /app/backend
|
||||
COPY --from=builder /app/migrations /app/migrations
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
litellm/vscode-extension
|
||||
litellm/proxy/discovery_endpoints/skill_scanner_adapter
|
||||
.github
|
||||
.github/*
|
||||
!.github/packaging/
|
||||
!.github/packaging/*.py
|
||||
tests
|
||||
.git
|
||||
.devcontainer
|
||||
|
|
@ -49,7 +51,7 @@ build/
|
|||
**/node_modules
|
||||
litellm/ui/litellm-dashboard/.next
|
||||
litellm/ui/litellm-dashboard/out
|
||||
litellm-rust/target/
|
||||
litellm/rust/target/
|
||||
litellm/rust_bridge/_native*.so
|
||||
*.log
|
||||
.env
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ echo
|
|||
pwd
|
||||
|
||||
|
||||
# only run this step for litellm enterprise, we run this if enterprise/enterprise_ui/_enterprise.json exists
|
||||
if [ ! -f "enterprise/enterprise_ui/enterprise_colors.json" ]; then
|
||||
# only run this step for litellm enterprise, we run this if litellm/enterprise/enterprise_ui/_enterprise.json exists
|
||||
if [ ! -f "litellm/enterprise/enterprise_ui/enterprise_colors.json" ]; then
|
||||
echo "Admin UI - using default LiteLLM UI"
|
||||
exit 0
|
||||
fi
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue