Skip to content

chore(typing): clear 2.7k basedpyright Any errors across 15 hotspot files - #34745

Merged
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_decrease_anys_fable
Jul 27, 2026
Merged

chore(typing): clear 2.7k basedpyright Any errors across 15 hotspot files#34745
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_decrease_anys_fable

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Backend Any counts keep drifting up toward their basedpyright ceilings
  • 15 hotspot files carried 3,105 reportAny/reportExplicitAny errors

How it solves it:

  • Real types at each Any source; zero casts, ignores, or suppressions
  • Prisma models, TypedDicts, and Protocols replace Any-typed dicts
  • Ratchets budgets down: basedpyright -2,869, ruff-strict -86, type-discipline -90
  • Raises the lint job's node heap so basedpyright survives the typed tree
  • Adds transformation tests for the retyped volcengine and evals modules

Relevant issues

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • 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)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Whole-tree basedpyright before and after this branch, measured with the same command the CI gate runs (uv run basedpyright --outputjson | python scripts/type_check_gate.py), counting severity=error diagnostics in-tree:

rule                 before   after   delta
reportAny            27,005   24,427  -2,578
reportExplicitAny     7,439    7,280    -159
all rules combined  157,700  154,832  -2,868

No basedpyright rule increased, repo-wide or in any individual file; every one of the 48 budgeted rules is at or below its baseline count. make lint-budget-update output confirming the fixes are real and the ceilings now hold them:

Ratcheted basedpyright limits down by 2869 errors this branch fixed across 48 rules
Ratcheted strict-rule limits down by 86 violations this branch fixed
Ratcheted LIT-rule limits down by 90 violations this branch fixed

from litellm import * import safety and the circular import check both pass, and make pre-commit is green

Type

🧹 Refactoring

Changes

Typing-only changes across the 15 files with the highest reportAny/reportExplicitAny density, plus the small blast radius those fixes surfaced in 7 neighboring files. No runtime behavior changes: annotations, TYPE_CHECKING imports, TypedDicts, Protocols, and pydantic model_validate swaps that are runtime-equivalent to the Model(**dict) constructors they replace

The recurring root causes and their fixes: untyped Prisma reads now go through typed helpers that pay the Any-to-typed crossing once per boundary (mcp_server/db.py, verification_token_repository.py); dict[str, Any] payloads became local TypedDicts (OAuth credential payloads, aggregated spend rows, guardrail usage responses); duck-typed spend records got a DailySpendRecord Protocol shared by the daily-activity endpoints; response transformation modules (volcengine, openai evals, azure batches, azure_ai count_tokens, ocr) now use the concrete request/response types they already imported

Forbidden constructs were not used anywhere in the diff: no cast(), no # type: ignore, no # noqa, no suppression comments, no new Any annotations. Diagnostics that could not be fixed without one of those were left in place rather than hidden, which is why roughly 380 target errors remain in the touched files (mostly the irreducible one-flag-per-seam residue where upstream sources like PrismaWrapper.__getattr__ still return Any)

Budget files are ratcheted by make lint-budget-update so the cleared headroom cannot silently grow back. The existing mapped suites for every touched module pass (1,140 tests, 0 failures)

Two follow-up commits round the PR out. 26ab846 raises the lint job's node heap to 12GB for the basedpyright budget step: with the hotspots now carrying real types, basedpyright's inference load exceeds node's ~4GB default cap on ubuntu-latest, so the process died with a JS heap OOM and the gate correctly refused the vacuous run (deterministic; a rerun at fbfb63c OOM'd the same way). 8b08c31 adds tests for the volcengine responses and openai evals transformation modules, covering the streaming field-fill heuristics, the model_construct fallbacks, and the get/cancel/delete/list request and response transforms that previously had no tests; these are retyped surfaces of this PR, and covering them also lifts the diff's patch coverage past the codecov target

QA runbook

  1. make lint-basedpyright lint-type-discipline lint-ruff-budget all green on this branch
  2. git diff litellm_internal_staging --stat shows only typing edits, budget JSONs, and no test deletions
  3. Boot the proxy (python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml) and confirm clean startup, then exercise a touched surface end to end, e.g. curl http://localhost:4000/user/daily/activity?start_date=2026-07-01&end_date=2026-07-25 -H "Authorization: Bearer sk-1234" and the MCP credential list at http://localhost:4000/ui/?page=mcp-servers; responses are byte-identical to litellm_internal_staging because no runtime code path changed

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Note

Low Risk
Refactor is typing-only with equivalent Pydantic validation patterns; main operational risk is CI memory for basedpyright, which this PR explicitly addresses.

Overview
This PR lowers basedpyright error ceilings in basedpyright-code-budget.json (notably reportAny and related rules) and sets NODE_OPTIONS=--max-old-space-size=12288 on the lint workflow’s basedpyright step so the heavier typed tree does not OOM in CI.

Across the code changes, the work is annotation and boundary typing, not new product behavior: modern union/list syntax, model_validate instead of **dict construction, and TYPE_CHECKING + Prisma model types with small DB accessor helpers (especially in MCP db.py and enterprise project endpoints). OAuth credential payloads get explicit TypedDicts; MCP REST/outbound OAuth stores use Mapping instead of loose dicts. LLM provider modules (Azure batches, OpenAI evals, Volcengine responses, Azure AI count_tokens, OCR) get stricter request/response typing and shared JSON-parse helpers where needed.

Reviewed by Cursor Bugbot for commit 8b08c31. Bugbot is set up for automated code reviews on this repo. Configure here.

…iles

Replace Any-typed seams with real types in the files carrying the highest
reportAny/reportExplicitAny density: typed Prisma read helpers in the MCP
db layer and verification token repository, TypedDicts for OAuth credential
payloads and aggregated spend rows, a DailySpendRecord protocol for the
daily activity endpoints, and concrete request/response types in the
volcengine, openai evals, azure batches, azure_ai count_tokens, and ocr
transformation modules. Modernize touched annotations to PEP 604/585 forms.

No casts, no type: ignore, no noqa, no new Any annotations, no behavior
changes. Whole-tree basedpyright: reportAny 27,005 -> 24,427,
reportExplicitAny 7,439 -> 7,280, no rule increased anywhere. Budgets
ratcheted: basedpyright -2,869, ruff-strict -1,505, type-discipline -167.
@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR strengthens static typing across provider transformations, MCP credential handling, management endpoints, usage aggregation, registries, and Prisma boundaries

  • Replaces loosely typed payloads with concrete models, TypedDicts, Protocols, and typed helper boundaries
  • Adds focused OpenAI evals and Volcengine response transformation tests
  • Ratchets static-analysis budgets downward and increases the basedpyright CI heap allocation

Confidence Score: 5/5

The PR appears safe to merge

No blocking failure remains

Important Files Changed

Filename Overview
litellm/proxy/_experimental/mcp_server/db.py Adds typed Prisma and OAuth credential boundaries while preserving the existing stored credential fields and refresh flow
litellm/proxy/_experimental/mcp_server/server.py Narrows MCP server and prefetched OAuth credential types without changing admission or dispatch behavior
litellm/proxy/management_endpoints/common_daily_activity.py Introduces typed spend-record and aggregate-row representations while retaining nullable SQL aggregate handling
litellm/proxy/guardrails/usage_endpoints.py Retypes guardrail usage aggregation and log transformation helpers
enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py Adds typed Prisma table access and Pydantic validation at project-management data boundaries
litellm/llms/openai/evals/transformation.py Uses concrete eval request and response models and adds transformation coverage
litellm/llms/volcengine/responses/transformation.py Retypes response parsing and field-fill transformations with expanded streaming and fallback tests
.github/workflows/test-linting.yml Raises the Node.js heap limit for the basedpyright budget check
basedpyright-code-budget.json Ratchets type-checking diagnostic ceilings downward to retain the reductions from this refactor

Reviews (2): Last reviewed commit: "test: cover volcengine responses and ope..." | Re-trigger Greptile

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit fbfb63c. Configure here.

@codspeed-hq

codspeed-hq Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_decrease_anys_fable (8b08c31) with litellm_internal_staging (bb6bb66)

Open in CodSpeed

@ryan-crabbe-berri ryan-crabbe-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks!

basedpyright's inference load now exceeds node's ~4GB default heap cap on
ubuntu-latest once the Any hotspots carry real types; the node process died
with a JS heap OOM, emitted nothing, and the gate refused the vacuous run.
12GB leaves headroom on the 16GB runner.
Exercises the streaming field-fill heuristics, model_construct fallbacks,
and the get/cancel/delete/list request and response transforms that had no
tests.
@mateo-berri
mateo-berri requested a review from a team July 27, 2026 19:57
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 8b08c31. Configure here.

@mateo-berri
mateo-berri merged commit 77ed122 into litellm_internal_staging Jul 27, 2026
81 checks passed
@mateo-berri
mateo-berri deleted the litellm_decrease_anys_fable branch July 27, 2026 20:23
TFSebben pushed a commit to TFSebben/litellm that referenced this pull request Aug 17, 2026
Replace Any-typed seams with real types in files carrying the highest
remaining reportAny/reportExplicitAny density after BerriAI#34745: the proxy
server and its utils, the router, the streaming handler and chunk builder,
litellm_logging, the redis cache, the MCP db/tool-registry/spend-writer
layer, the anthropic pass-through adapters and guardrail translation, the
lasso and presidio guardrail hooks, the azure_ai agents handler, the
management endpoints (keys, users, ui_sso, model access groups, config
override, MCP, projects), the responses MCP handlers, response polling
background streaming, and the containers and vector stores mains

No casts, no type: ignore, no noqa, no new suppressions, and no Any
annotations that were not already at base. Whole-tree basedpyright:
reportAny 14,610 -> 14,009, reportExplicitAny 5,100 -> 4,780, total
144,743 -> 143,471, with no rule increasing repo-wide or in any file.
Budgets ratcheted: basedpyright -1,272 across 48 rules, ruff-strict -85,
type-discipline -37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants