mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
* feat(complexity_router): custom classifier plugins via classifier_type 'plugin' Adds a third classification mode where an operator-supplied hook decides the tier instead of the heuristic scorer or the LLM classifier. The hook implements an async classify(context) returning a tier name (built-in value, tier_labels label, or tier_definitions name) or None to decline; failures, timeouts, and unknown tiers fall back exactly like a failed LLM classifier. The context carries the request messages and metadata, including caller identity, so a plugin can route by team, spend, or any business rule. The plugin resolves from a dotted path at proxy startup with a load-time check that classify is a coroutine function, and is closed off over HTTP like the routing plugins list. Routing decisions record the new classifier_plugin cause. tier_definitions now accepts classifier_type 'plugin' alongside 'llm'. * fix(proxy): resolve plugin dotted paths in _delete_deployment before hashing ids The db-sync reconcile re-reads the raw config and hashes litellm_params to compute which ids the config wants served, but the router's ids were hashed from the resolved params where plugin dotted paths are live instances. The mismatched ids made the reconcile evict every plugin-bearing auto-router one sync after startup, on any proxy with a database connected. This also affected the existing routing plugins list, not just the new classifier plugin. Resolving the plugins in _delete_deployment the same way load_config does makes both sides hash the same canonical form. A plugin module broken on disk at reconcile time skips cleanup instead of evicting valid deployments, matching how a get_config failure is handled * fix(complexity_router): treat non-string plugin verdicts as declines, centralize the empty-mapping sentinel A hook returning a non-string raised inside resolve_classified_tier outside the plugin exception boundary, failing the request instead of falling back. Also moves the read-only empty mapping to constants.py per repo convention and moves the classifier plugin product docs out of the package README for the docs repo * refactor(complexity_router): rename the plugin classifier mode to classifier_type 'custom' The mode value now names the operator's intent while classifier_plugin keeps naming the mechanism; routing decisions keep the classifier_plugin cause * refactor(proxy): pin plugin-bearing deployment ids from the raw params instead of resolving in the reconcile Replaces the previous approach of re-running plugin resolution inside _delete_deployment, which imported operator modules on every reconcile cycle and skipped the whole cleanup pass when any one module was broken on disk. load_config now stamps model_info.id from the raw litellm_params before resolution swaps dotted paths for live instances, so the reconcile's raw-config hash matches by construction and needs no resolution at all: a broken module cannot stall cleanup for unrelated models, and any future param-transforming resolution is covered by the same pin. _generate_model_id becomes a staticmethod so the pin can run before the Router exists; its statically dead non-string key branches are removed. Also documents candidate_models as an informational snapshot for classifier plugins, unlike the narrowing surface RoutingPlugin filters * fix(router): restore _generate_model_id key handling, align classifier context with the routing-plugin pattern The staticmethod conversion accidentally dropped the non-string-key branches from _generate_model_id, a silent hash change for any params with non-string keys; they are restored verbatim. The classifier plugin context now follows the Router-level routing-plugin recipe exactly: structured messages come from resolve_structured_messages over the raw messages, and the metadata key comes from the shared get_metadata_variable_name_from_kwargs helper, which also replaces the duplicated inline sniff in _pick_model_for_tier. This removes the raw-or-resolved fallback where a plugin could silently receive resolved messages when a call site forgot to pass the raw ones * refactor(router): make generate_model_id public, guard classifier context construction Two modules legitimately hash deployment ids with the same helper now (Router and the proxy's config-load pin), so the private name was lying about its audience and the cross-module call needed a pyright suppression; renaming it public restores the static safety net. The classifier plugin's RoutingContext construction moves inside the failure boundary, matching the LLM path where litellm-side prompt building also falls back rather than failing the request, and a prompt-only call with no message list is now covered by a test |
||
|---|---|---|
| .. | ||
| conftest.py | ||
| create_mock_standard_logging_payload.py | ||
| gettysburg.wav | ||
| README.md | ||
| test_completion_no_copy.py | ||
| test_default_deployment_copy.py | ||
| test_get_model_list_alias_optimization.py | ||
| test_pre_call_checks_optimization.py | ||
| test_prompt_management_check.py | ||
| test_router_acancel_batch.py | ||
| test_router_adding_deployments.py | ||
| test_router_aresponses_streaming_fallback.py | ||
| test_router_batch_utils.py | ||
| test_router_cooldown_per_deployment.py | ||
| test_router_cooldown_utils.py | ||
| test_router_embedding_headers.py | ||
| test_router_embedding_integration.py | ||
| test_router_endpoints.py | ||
| test_router_handle_error.py | ||
| test_router_helper_utils.py | ||
| test_router_index_management.py | ||
| test_router_prompt_caching.py | ||
Router component unit tests.
Please name all files with the word 'router' in them.
This is used to ensure all functions in the router are tested.