Skip to content

Commit d5ac495

Browse files
committed
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_batch_enqueued_token_limit
2 parents 2a771ca + c2b3c4b commit d5ac495

388 files changed

Lines changed: 24411 additions & 11618 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/scripts/classify_changes.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
#!/usr/bin/env bash
22
set -uo pipefail
33

4-
category="${1:?usage: classify_changes.sh <backend|client>}"
4+
category="${1:?usage: classify_changes.sh <backend|client|ui>}"
55

66
has_client=false
77
has_backend=false
8+
has_ci=false
89
while IFS= read -r file || [ -n "$file" ]; do
910
[ -n "$file" ] || continue
1011
case "$file" in
1112
ui/* | tests/e2e/ui/*) has_client=true ;;
1213
docs/* | *.md | *.mdx) : ;;
14+
.github/* | .circleci/*) has_ci=true; has_backend=true ;;
1315
*) has_backend=true ;;
1416
esac
1517
done
@@ -21,6 +23,9 @@ case "$category" in
2123
client)
2224
{ [ "$has_client" = true ] || [ "$has_backend" = true ]; } && echo run || echo skip
2325
;;
26+
ui)
27+
{ [ "$has_client" = true ] || [ "$has_ci" = true ]; } && echo run || echo skip
28+
;;
2429
*)
2530
echo run
2631
;;

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
/ui/ @yuneng-jiang @ryan-crabbe-berri
22
/litellm/proxy/_experimental/out/ @yuneng-jiang @ryan-crabbe-berri
33
/ui/litellm-dashboard/src/lib/http/schema.d.ts
4+
/model_prices_and_context_window.json @mateo-berri
5+
/litellm/model_prices_and_context_window_backup.json @mateo-berri

.github/actions/detect-backend-changes/action.yml

Lines changed: 0 additions & 48 deletions
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: "Detect relevant changes"
2+
description: >-
3+
Classify the pull request's changed files with .circleci/scripts/classify_changes.sh
4+
and expose decision=run|skip for one category. backend means anything outside ui/,
5+
docs/ and markdown; ui means the dashboard sources alone. decision=skip lets callers
6+
short-circuit expensive steps while the job still completes successfully and satisfies
7+
its required status check, which a paths: filter cannot do because a workflow that
8+
never starts never reports. The file list comes from the pull request itself rather
9+
than from a git diff, because the checked-out merge ref is recomputed as the base
10+
branch advances and would otherwise attribute the base branch's own commits to the
11+
pull request. The decision defaults to run for any non pull_request event or whenever
12+
the changed set cannot be resolved, so jobs are never skipped when the classification
13+
is uncertain.
14+
15+
inputs:
16+
category:
17+
description: "Which classification to apply: backend, client or ui"
18+
required: false
19+
default: backend
20+
github-token:
21+
description: "Token used to list the pull request's files; needs pull-requests: read"
22+
required: false
23+
default: ${{ github.token }}
24+
25+
outputs:
26+
decision:
27+
description: "run when category-relevant files changed, otherwise skip"
28+
value: ${{ steps.classify.outputs.decision }}
29+
30+
runs:
31+
using: composite
32+
steps:
33+
- id: classify
34+
shell: bash
35+
env:
36+
GH_TOKEN: ${{ inputs.github-token }}
37+
CATEGORY: ${{ inputs.category }}
38+
REPO: ${{ github.repository }}
39+
PR_NUMBER: ${{ github.event.pull_request.number }}
40+
CHANGED_FILE_COUNT: ${{ github.event.pull_request.changed_files }}
41+
run: bash "${GITHUB_ACTION_PATH}/../../scripts/detect_changes.sh"

.github/pull_request_template.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ After: the same request comes back with real token counts, so the dashboard show
5353
**Please complete all items before asking a LiteLLM maintainer to review your PR**
5454

5555
- [ ] I have added meaningful tests
56-
- [ ] My PR passes all CI/CD checks (e.g., lint, format, unit tests)
56+
- [ ] The handful of test files covering my change pass locally, e.g. `uv run pytest tests/test_litellm/<your_test_file>.py -v`. Leave the suites (`make test-unit-*`, `make test-unit`) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
57+
- [ ] My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
5758
- [ ] My PR's scope is as isolated as possible; it only solves 1 specific problem
5859
- [ ] I have received a Greptile **Confidence Score of at least 4/5** before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment `@greptileai` to re-request a review after pushing changes)
5960

.github/scripts/detect_changes.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env bash
2+
set -uo pipefail
3+
4+
readonly API_FILE_CEILING=3000
5+
readonly CATEGORY="${CATEGORY:-backend}"
6+
7+
decide() {
8+
echo "detect-changes[${CATEGORY}]: decision=$1"
9+
[ -z "${GITHUB_OUTPUT:-}" ] || echo "decision=$1" >>"${GITHUB_OUTPUT}"
10+
exit 0
11+
}
12+
13+
run_full() {
14+
echo "detect-changes[${CATEGORY}]: $1; running job"
15+
decide run
16+
}
17+
18+
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19+
classify="${here}/../../.circleci/scripts/classify_changes.sh"
20+
21+
[ -n "${PR_NUMBER:-}" ] || run_full "not a pull_request event"
22+
[ -n "${REPO:-}" ] || run_full "no repository in the environment"
23+
24+
case "${CHANGED_FILE_COUNT:-}" in
25+
'' | *[!0-9]*) run_full "the event payload carries no changed_files count" ;;
26+
esac
27+
[ "${CHANGED_FILE_COUNT}" -le "${API_FILE_CEILING}" ] ||
28+
run_full "PR #${PR_NUMBER} changes ${CHANGED_FILE_COUNT} files, past the ${API_FILE_CEILING}-file listing ceiling"
29+
30+
changed="$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/files" --paginate --jq '.[].filename')" ||
31+
run_full "could not list the files on PR #${PR_NUMBER}"
32+
[ -n "${changed}" ] || run_full "the API listed no files on PR #${PR_NUMBER}"
33+
34+
echo "detect-changes[${CATEGORY}]: files changed by PR #${PR_NUMBER}:"
35+
printf '%s\n' "${changed}" | sed 's/^/ /'
36+
37+
decision="$(printf '%s\n' "${changed}" | bash "${classify}" "${CATEGORY}")" ||
38+
run_full "classify_changes.sh failed"
39+
case "${decision}" in
40+
run | skip) decide "${decision}" ;;
41+
*) run_full "classify_changes.sh printed an unexpected decision: ${decision}" ;;
42+
esac

.github/workflows/_test-unit-base.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ jobs:
6060
name: Run tests
6161
runs-on: ubuntu-latest
6262
timeout-minutes: ${{ inputs.job-timeout-minutes }}
63+
permissions:
64+
contents: read
65+
pull-requests: read
6366
outputs:
6467
decision: ${{ steps.changes.outputs.decision }}
6568

@@ -69,24 +72,27 @@ jobs:
6972
with:
7073
persist-credentials: false
7174

72-
- name: Detect backend-relevant changes
75+
- name: Detect relevant changes
7376
id: changes
7477
timeout-minutes: 2
75-
uses: ./.github/actions/detect-backend-changes
78+
uses: ./.github/actions/detect-changes
7679

7780
- name: Set up Python
81+
if: steps.changes.outputs.decision != 'skip'
7882
timeout-minutes: 3
7983
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
8084
with:
8185
python-version: "3.12"
8286

8387
- name: Set up uv
88+
if: steps.changes.outputs.decision != 'skip'
8489
timeout-minutes: 3
8590
uses: ./.github/actions/setup-uv-with-retries
8691
with:
8792
version: "0.10.9"
8893

8994
- name: Cache uv dependencies
95+
if: steps.changes.outputs.decision != 'skip'
9096
timeout-minutes: 5
9197
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
9298
with:

.github/workflows/test-linting.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
# re-running basedpyright over the merge-base tree.
2525
permissions:
2626
contents: read
27+
pull-requests: read
2728
actions: read
2829

2930
steps:
@@ -37,7 +38,12 @@ jobs:
3738
clean: true
3839
persist-credentials: false
3940

41+
- name: Detect relevant changes
42+
id: changes
43+
uses: ./.github/actions/detect-changes
44+
4045
- name: Fetch gate base (merge-base with target branch)
46+
if: steps.changes.outputs.decision != 'skip'
4147
env:
4248
GH_TOKEN: ${{ github.token }}
4349
BASE_SHA: ${{ github.event.pull_request.base.sha }}
@@ -50,39 +56,47 @@ jobs:
5056
echo "GATE_BASE_SHA=$MERGE_BASE" >> "$GITHUB_ENV"
5157
5258
- name: Set up Python
59+
if: steps.changes.outputs.decision != 'skip'
5360
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
5461
with:
5562
python-version: "3.12"
5663

5764
- name: Set up uv
65+
if: steps.changes.outputs.decision != 'skip'
5866
uses: ./.github/actions/setup-uv-with-retries
5967
with:
6068
version: "0.10.9"
6169

6270
- name: Clean Python cache
71+
if: steps.changes.outputs.decision != 'skip'
6372
run: |
6473
find . -type d -name "__pycache__" -exec rm -rf {} + || true
6574
find . -name "*.pyc" -delete || true
6675
6776
- name: Check uv.lock is up to date
77+
if: steps.changes.outputs.decision != 'skip'
6878
run: |
6979
uv lock --check || (echo "❌ uv.lock is out of sync with pyproject.toml. Run 'uv lock' locally and commit the result." && exit 1)
7080
7181
- name: Install dependencies
82+
if: steps.changes.outputs.decision != 'skip'
7283
run: |
7384
uv sync --frozen --group proxy-dev --group e2e-dev
7485
7586
- name: Cache Prisma binaries
87+
if: steps.changes.outputs.decision != 'skip'
7688
uses: ./.github/actions/cache-prisma-binaries
7789

7890
# basedpyright resolves Prisma's generated client (litellm/proxy/schema.prisma)
7991
# only after `prisma generate` writes prisma/client.py et al. Without this the
8092
# DB wrappers typed against the generated client would degrade to Unknown.
8193
- name: Generate Prisma client
94+
if: steps.changes.outputs.decision != 'skip'
8295
run: |
8396
uv run --no-sync prisma generate --schema litellm/proxy/schema.prisma
8497
8598
- name: Check ruff format
99+
if: steps.changes.outputs.decision != 'skip'
86100
run: |
87101
git diff --name-only --diff-filter=ACMR "$GATE_BASE_SHA" HEAD -- 'litellm/**/*.py' | grep -v '^litellm/enterprise/' > "$RUNNER_TEMP/ruff_format_files.txt" || true
88102
if [ ! -s "$RUNNER_TEMP/ruff_format_files.txt" ]; then
@@ -92,6 +106,7 @@ jobs:
92106
xargs uv run --no-sync ruff format --check --exclude '/enterprise/' < "$RUNNER_TEMP/ruff_format_files.txt"
93107
94108
- name: Debug - Check file state
109+
if: steps.changes.outputs.decision != 'skip'
95110
run: |
96111
echo "Current branch:"
97112
git branch --show-current
@@ -101,30 +116,36 @@ jobs:
101116
head -50 litellm/litellm_core_utils/custom_logger_registry.py | tail -10
102117
103118
- name: Run Ruff linting
119+
if: steps.changes.outputs.decision != 'skip'
104120
run: |
105121
cd litellm
106122
uv run --no-sync ruff check .
107123
cd ..
108124
109125
- name: Check strict-rule budget (delta vs base)
126+
if: steps.changes.outputs.decision != 'skip'
110127
run: |
111128
uv run --no-sync python scripts/ruff_strict_gate.py --base "$GATE_BASE_SHA"
112129
113130
- name: Check type-discipline budget (mutable collections / casts / type guards / kwargs / unexplained suppressions, delta vs base)
131+
if: steps.changes.outputs.decision != 'skip'
114132
run: |
115133
uv run --no-sync python scripts/type_discipline_gate.py --base "$GATE_BASE_SHA"
116134
117135
- name: Print OpenAI version
136+
if: steps.changes.outputs.decision != 'skip'
118137
run: |
119138
uv run --no-sync python -c "import openai; print(f'OpenAI version: {openai.__version__}')"
120139
121140
- name: Check basedpyright budget (delta vs base)
141+
if: steps.changes.outputs.decision != 'skip'
122142
env:
123143
GH_TOKEN: ${{ github.token }}
124144
run: |
125145
uv run --no-sync python scripts/type_check_gate.py --base "$GATE_BASE_SHA"
126146
127147
- name: Check tests/e2e basedpyright (zero errors)
148+
if: steps.changes.outputs.decision != 'skip'
128149
run: |
129150
if git diff --name-only --diff-filter=ACMRD "$GATE_BASE_SHA" HEAD -- 'tests/e2e/**/*.py' | grep -q .; then
130151
uv run --no-sync basedpyright tests/e2e
@@ -133,12 +154,14 @@ jobs:
133154
fi
134155
135156
- name: Check for circular imports
157+
if: steps.changes.outputs.decision != 'skip'
136158
run: |
137159
cd litellm
138160
uv run --no-sync python ../tests/documentation_tests/test_circular_imports.py
139161
cd ..
140162
141163
- name: Check import safety
164+
if: steps.changes.outputs.decision != 'skip'
142165
run: |
143166
uv run --no-sync python -c "from litellm import *" || (echo '🚨 import failed, this means you introduced unprotected imports! 🚨'; exit 1)
144167

.github/workflows/test-litellm-ui-build.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: UI Build Check
22
permissions:
33
contents: read
4+
pull-requests: read
45

56
on:
67
pull_request:
@@ -28,15 +29,24 @@ jobs:
2829
with:
2930
persist-credentials: false
3031

32+
- name: Detect relevant changes
33+
id: changes
34+
uses: ./.github/actions/detect-changes
35+
with:
36+
category: ui
37+
3138
- name: Setup Node.js
39+
if: steps.changes.outputs.decision != 'skip'
3240
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
3341
with:
3442
node-version-file: ui/litellm-dashboard/.nvmrc
3543
cache: "npm"
3644
cache-dependency-path: ui/litellm-dashboard/package-lock.json
3745

3846
- name: Install dependencies
47+
if: steps.changes.outputs.decision != 'skip'
3948
run: npm ci
4049

4150
- name: Build
51+
if: steps.changes.outputs.decision != 'skip'
4252
run: npm run build

0 commit comments

Comments
 (0)