Commit Graph
31 Commits
Author SHA1 Message Date
51876292a0 Litellm ishaan april4 2 (#25150)
* feat(router): integrate allowed_fails_policy into health check failures (#24988)

* feat(router): integrate allowed_fails_policy into health check failures

Health check failures now increment the same per-deployment failure
counters used by allowed_fails_policy, so users can control how many
health check failures of each error type are required before a
deployment enters cooldown.

- ahealth_check() preserves the original exception in its return dict
- run_with_timeout() returns a litellm.Timeout on health check timeout
- _perform_health_check() propagates exceptions to unhealthy endpoints
- _write_health_state_to_router_cache() calls _set_cooldown_deployments
  for each unhealthy endpoint that has an exception
- When allowed_fails_policy is set, the binary health check filter is
  bypassed so cooldown is the sole routing exclusion mechanism
- Safety net: if all deployments are in cooldown with
  enable_health_check_routing=True, the cooldown filter is bypassed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(router): add health_check_ignore_transient_errors flag

When enabled, health check failures with 429 (rate limit) or 408 (timeout)
status codes are skipped from the cooldown pipeline. These are transient
load issues, not broken deployments. Auth errors (401), 404, and 5xx errors
still increment counters and trigger cooldown as before.

Config (general_settings):
  health_check_ignore_transient_errors: true

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(router): also exclude 429/408 from health state cache when ignore_transient_errors set

The previous fix only skipped cooldown counter increments. The health state
cache was still marking 429/408 endpoints as is_healthy=False, causing the
binary health check filter to exclude them from routing.

Now, when health_check_ignore_transient_errors=True, 429/408 endpoints are
also excluded from the unhealthy list passed to build_deployment_health_states(),
so the binary filter treats them as unaffected (not unhealthy).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs(router): add health check driven routing guide

New standalone page covering the full health check routing feature:
allowed_fails_policy integration, health_check_ignore_transient_errors,
architecture SVG, step-by-step setup, and gotchas (TTL, AllowedFails semantics).

Replaces the inline section in health.md with a link to the new page.
Added to the Routing & Load Balancing sidebar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(health-check-routing): fix three CI failures

- Add "exception" to ILLEGAL_DISPLAY_PARAMS in health_check.py so the
  exception object is stripped before the health endpoint serializes
  results to JSON (fixes TypeError: 'URL' object is not iterable)
- Add allowed_fails_policy = None to FakeRouter stubs in
  test_router_health_check_routing.py (fixes AttributeError)
- Add health_check_ignore_transient_errors to config_settings.md router
  settings reference table (fixes documentation test)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix litellm/tests/proxy_unit_tests/test_proxy_server.py

* fix(router): address greptile review comments

- Narrow cooldown safety-net bypass: only fires when allowed_fails_policy
  is set (cooldown is health-check driven). Without a policy, cooldowns
  are from real request failures and must not be bypassed.
- Restore cooldown deployments DEBUG log that was accidentally removed.
- Fix test_health TypeError: move exception extraction to a separate
  exceptions_by_model_id dict returned alongside endpoints, so exception
  objects never appear in the endpoint dicts that get JSON-serialized
  by the /health response.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(health-check-routing): properly isolate exceptions from health response

Return exceptions_by_model_id as a separate third value from
_perform_health_check / perform_health_check so exception objects
(which contain non-JSON-serializable httpx URL types) never appear
in the endpoint dicts that get serialized by the /health response.

Callers updated: _health_endpoints.py, shared_health_check_manager.py,
proxy_server.py background loop. All use the exceptions dict only for
cooldown integration, not for display.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(shared-health-check): fix remaining 2-value return sites and update type annotation

* fix(health-check-routing): fix P0 cooldown integration never firing

The cooldown loop was reading endpoint.get("exception") which is always
None because exceptions are now returned via exceptions_by_model_id, not
stored in endpoint dicts. Fixed to use _exceptions.get(model_id).

Also fixes the transient-error filter to use _exceptions instead of
endpoint.get("exception"), and fixes all remaining 2-value return sites
in shared_health_check_manager.py. Tests updated to pass exceptions via
exceptions_by_model_id parameter instead of endpoint dicts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(health-check-routing): fix P1 transient-error filter broken on cache hits

When SharedHealthCheckManager returns cached results, exceptions_by_model_id
is always {} so the transient-error filter defaulted to status 500 for all
endpoints, incorrectly marking 429/408 endpoints as unhealthy.

Fix: store integer exception_status on each unhealthy endpoint dict in
_perform_health_check. _get_endpoint_exception_status() uses the live
exception object when available (direct path) and falls back to the stored
integer (cache-hit path). The integer is JSON-serializable and survives
the shared cache round-trip.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(health-check-routing): gate cooldown loop behind allowed_fails_policy

Without the policy, cooldown is not the routing exclusion mechanism.
Firing _set_cooldown_deployments for all enable_health_check_routing users
was a backwards-incompatible change — 401s would immediately cooldown
deployments that the binary filter would have recovered on the next cycle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* revert: undo allowed_fails_policy gate on cooldown loop

Cooldown integration via health checks is intentional for all
enable_health_check_routing users, not just those with allowed_fails_policy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docs+tests): fix health_check_ignore_transient_errors doc section and test coverage

- Move health_check_ignore_transient_errors from router_settings to
  general_settings in config_settings.md (code reads it from general_settings)
- Remove duplicate enable_health_check_routing / health_check_staleness_threshold
  entries that were incorrectly listed under router_settings
- Replace TestHealthCheckEndpointExceptionPropagation tests with ones that
  exercise the real _perform_health_check code path via mocked ahealth_check,
  verifying exceptions appear in exceptions_by_model_id and NOT in endpoint dicts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tests+docs): fix tuple unpacking and docs test failures

- Update test mocks that return (healthy, unhealthy) to return
  (healthy, unhealthy, {}) to match the new 3-value signature
- Update test unpackings of perform_shared_health_check to use
  healthy, unhealthy, _ = ...
- Add health_check_ignore_transient_errors to router_settings section
  in config_settings.md (it is a Router constructor param, so the doc
  test requires it there; it also lives in general_settings for proxy use)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix CodeQL errors

* fix(tests): fix 2-value unpackings of _perform_health_check in test_health_check.py

* fix(tests): fix mock _perform_health_check returning 2-tuple instead of 3

* fix team routing

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add distributed lock for key rotation job (#23364)

* fix: add distributed lock for key rotation job

* fix: address Greptile review feedback on key rotation lock (#23834)

* fix: address Greptile review feedback on key rotation lock

* fix req changes greptile

* feat(proxy): Optional on_error for guardrail pipeline (API / technical failures) (#24831)

* guardrails fallback

* docs

* docs: add LITELLM_KEY_ROTATION_LOCK_TTL_SECONDS to environment variables reference

* fix(mypy): accept Union[Dict, Any] in _get_deployment_order and use typed list to fix min() type error

* fix(mypy): use Optional[str] for api_base in PydanticAI provider to match superclass signature

---------

Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Harshit Jain <48647625+Harshit28j@users.noreply.github.com>
Co-authored-by: Shivam Rawat <shivam@berri.ai>
Co-authored-by: yuneng-jiang <yuneng@berri.ai>
2026-04-04 23:09:42 +00:00
Yuneng JiangandClaude Opus 4.6 fc32f91ffd [Fix] Rename test file so router code coverage check detects it
The router_code_coverage.py script only scans test files with "router" in the filename.
test_health_check_routing.py was invisible to this check, causing _async_filter_health_check_unhealthy_deployments
and _filter_health_check_unhealthy_deployments to appear untested.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:13:41 -07:00
Sameer KankuteandClaude Opus 4.6 7675488640 feat(router): add health-check-driven routing behind opt-in flag
Background health checks now feed deployment health state into the
router candidate-filtering pipeline. Unhealthy deployments are excluded
proactively instead of waiting for request failures to trigger cooldown.

Gated by `enable_health_check_routing: true` in general_settings.
Off by default — zero behavior change for existing users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 20:57:08 +05:30
Sameer KankuteandClaude Haiku 4.5 528daa8cf4 feat(router): add per-model-group deployment affinity configuration
Enable deployment_affinity, responses_api_deployment_check, and session_affinity to be configured per model group via router_settings.model_group_affinity_config, falling back to global settings for unconfigured groups.

- Add model_group_affinity_config parameter to Router and DeploymentAffinityCheck
- Add _get_effective_flags helper to resolve flags per model group
- Update async_filter_deployments and async_pre_call_deployment_hook to use per-group config
- Add 4 comprehensive tests covering per-group config, fallback, and override scenarios

This allows fine-grained control of affinity behavior across model groups, e.g., enabling stickiness only for cross-provider deployments while leaving other groups free to load-balance.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 14:44:01 +05:30
yuneng-jiangandClaude Opus 4.6 1092c17468 Fix flaky encrypted_content_affinity tests: mock at handler level
The 4 integration tests were flaky in CI because the AsyncHTTPHandler.post
mock was bypassed when aiohttp transport is used. Mock at the higher
BaseLLMHTTPHandler.async_response_api_handler level instead, which
bypasses the HTTP layer entirely while still exercising router deployment
selection, pre-call checks, and response post-processing (item ID rewriting).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:39:25 -07:00
yuneng-jiangandClaude Opus 4.6 67e905f0d0 Fix flaky encrypted_content_affinity tests: clear HTTP client cache, disable retries
Tests failed intermittently in CI (-n 8 workers) because cached
AsyncHTTPHandler instances from other tests bypassed the class-level
mock on AsyncHTTPHandler.post, causing real requests to OpenAI with
mock API keys. Router retries (default 2) masked the root cause.

- Add autouse fixture to flush litellm.in_memory_llm_clients_cache
  before/after each test so mocks always apply to fresh clients
- Set num_retries=0 on all Router instances to surface mock failures
  immediately instead of silently retrying

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:18:34 -07:00
Sameer Kankute 521f804350 Fix encrypted content streaming affinity issue 2026-03-03 18:37:22 +05:30
Sameer Kankute 2bc4da76ce Update the tests 2026-03-03 18:36:07 +05:30
Sameer Kankute 18bf3f2df6 Fix mock github test 2026-03-03 18:36:07 +05:30
Sameer Kankute a88a17796b Fix logging and encrypted content extraction 2026-03-03 18:36:07 +05:30
Sameer Kankute 9f627c67d8 Add tests for encrypted_content_affinity 2026-03-03 18:36:07 +05:30
Sameer Kankute 394c49d303 Add tests for encrypted_content_affinity 2026-03-03 18:36:07 +05:30
Sameer Kankute 7cda0e4edd Fix code qa 2026-02-26 12:43:06 +05:30
Harshit Jain 456d8f5524 feat: add session_id to have better routing 2026-02-21 18:45:50 +05:30
Emerson Gomes 3dd55a7b61 Merge main into affinity_callback and address deployment affinity review feedback 2026-02-18 10:01:11 -06:00
Emerson Gomes f7726c8950 Fix wrong keys being used for model sticky entry 2026-01-15 17:42:29 -06:00
Emerson Gomes 059e75ad88 fix(router): scope deployment affinity by model_map_key
- Key affinity by (user_api_key_hash, model_map_key) -> model_id
- Ignore OpenAI 'user' param for affinity
- Avoid double hashing user_api_key_hash
- Add unit tests + docs clarifications
2026-01-15 16:28:36 -06:00
Emerson Gomes e23bd21a28 Add deployment affinity routing 2026-01-15 08:53:31 -06:00
Ishaan JaffandGitHub 539f629eff [Feat] New Logging Integration - Azure Sentinel Logger (#18146)
* add AzureSentinelLogger

* logging: AzureSentinelLogger

* test_azure_sentinel_signature_and_send_batch

* docs azure sentinel

* fix AzureSentinelLogger

* test fix

* docs fix

* fix: AzureSentinelLogger

* docs sentintel

* feat: add example SLP

* docs sentinel

* docs fix

* docs fix

* docs fix

* fix code qa

* QA fix

* fix test

* TestInitializeInteractionsEndpoints
2025-12-18 02:04:49 +05:30
Cesar GarciaandGitHub 7c2e2111c0 fix(router): handle tools=None in filter_web_search_deployments (#17684)
Fixes #17672

Changed `request_kwargs.get("tools", [])` to `request_kwargs.get("tools") or []`
to handle the case where tools is explicitly set to None.
2025-12-08 18:36:46 -08:00
Raghav JhavarandGitHub 72eb4c3a1c 🆕 feat: support routing to only websearch supported deployments (#17500)
* support routing to only websearch supported deployments

* add docs
2025-12-04 14:18:20 -08:00
Sameer KankuteandGitHub f804ab6de5 Add LLM provider response headers to Responses API (#16091)
* Add llm headers to responses api

* fix mock test
2025-11-01 13:25:56 -07:00
Ishaan Jaff d89a2a0797 test 2025-09-06 16:38:43 -07:00
Ishaan Jaff c168fff38a test_cooldown_badrequest_error 2025-09-06 16:28:00 -07:00
Ishaan Jaff 7054067238 test_cooldown_handlers.py 2025-09-06 16:13:30 -07:00
Krish DholakiaandGitHub 3b52545db3 Merge pull request #13529 from BerriAI/litellm_dev_08_11_2025_p1
[Fix] Cooldowns - don't return raw Azure Exceptions to client
2025-08-18 18:54:19 -07:00
Ishaan JaffandGitHub 76f1064229 [Bug Fix] litellm incompatible with newest release of openAI v1.100.0 (#13728)
* fix imports OpenAI SDK

* ResponseText fixes

* fixes ResponseText

* fix imports

* catch AttributeError

* fix import

* use openai==1.100.1

* fix build from PIP

* fix lint test

* Print OpenAI version

* fix Install dependencies
2025-08-18 18:26:17 -07:00
Krrish Dholakia bc9d0484e4 fix(cooldown_cache.py): mask error string to avoid leaking sensitive prompt data
Fixes https://github.com/BerriAI/litellm/issues/13329
2025-08-11 18:37:57 -07:00
Ishaan JaffandGitHub 39955129f5 fix mapped tests (#12320)
* fix - use flush llm client cache

* faster mapped tests

* test_async_multiple_response_ids_routing

* fix tests

* test_ateam_member_update_admin_requires_premium

* regular mapped tests

* Revert "Fix: Initialize JSON logging for all loggers when JSON_LOGS=True (#12206)"

This reverts commit 2c60c316ec.

* reset num workers
2025-07-04 10:04:43 -07:00
Krish DholakiaandGitHub 1a7fd1d1c7 Litellm dev 06 25 2025 p2 (#12049)
* test(test_router.py): initial unit test confirming router.afile_content uses dynamic api key / api base

* fix(managed_files.py): filter deployments for only those within file id mapping

ensure call works - only route to models where the file was written

* fix(proxy_server.py): fix loading in model ids from config, if config id is int

* fix(router.py): return all model file id mappings on create_file

if multiple deployments - this ensures all the file id mappings are bubbled up

Fixes issue when trying to use loadbalanced deployments - only 1 file id mapping was being stored

* feat(router_utils/common_utils.py): filter models by team id when selecting for routing

Prevents team only models from being used by other teams

* fix(common_utils.py): additional fixes around filtering team-based models

* fix(batches_endpoints/endpoints): support list batches with target model names specified

* fix(common_utils.py): more testing for team deployment filters
2025-06-25 21:54:13 -07:00
Krish DholakiaandGitHub ef42461c1e Litellm fix GitHub action testing (#11163)
* test: add __init__.py files

* refactor: rename test folder to avoid naming conflict

* test: update workflows

* test: update tests

* test: update imports

* test: update tests

* test: remove unused import

* ci(test-litellm.yml): add pytest retry to github workflow

* test: fix test
2025-05-26 14:41:42 -07:00