mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-10 08:28:25 +00:00
Merge 6558ffe749 into 9b1d69e32c
This commit is contained in:
commit
86bb981069
15 changed files with 24 additions and 295 deletions
8
.github/workflows/test-unit.yml
vendored
8
.github/workflows/test-unit.yml
vendored
|
|
@ -999,9 +999,9 @@ jobs:
|
|||
run: |
|
||||
diff -u model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
|
||||
if [ -z "$RUST_BRIDGE_ARTIFACT" ]; then
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra caching --extra extra_proxy --extra proxy-runtime --extra utils
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra extra_proxy --extra proxy-runtime --extra utils
|
||||
else
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra caching --extra extra_proxy --extra proxy-runtime --extra utils --no-install-project
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra extra_proxy --extra proxy-runtime --extra utils --no-install-project
|
||||
uv pip install --no-deps --python .venv/bin/python rust-bridge-dist/*.whl
|
||||
cp rust-bridge-dist/litellm/rust_bridge/_native.abi3.so litellm/rust_bridge/_native.abi3.so
|
||||
uv run --no-sync python -c "import importlib.metadata; import litellm.rust_bridge._native; print(importlib.metadata.version('litellm'))"
|
||||
|
|
@ -1437,9 +1437,9 @@ jobs:
|
|||
RUST_BRIDGE_ARTIFACT: ${{ needs.rust-bridge.outputs.artifact }}
|
||||
run: |
|
||||
if [ -z "$RUST_BRIDGE_ARTIFACT" ]; then
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra caching --extra extra_proxy --extra proxy-runtime --extra utils
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra extra_proxy --extra proxy-runtime --extra utils
|
||||
else
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra caching --extra extra_proxy --extra proxy-runtime --extra utils --no-install-project
|
||||
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml --extra extra_proxy --extra proxy-runtime --extra utils --no-install-project
|
||||
uv pip install --no-deps --python .venv/bin/python rust-bridge-dist/*.whl
|
||||
cp rust-bridge-dist/litellm/rust_bridge/_native.abi3.so litellm/rust_bridge/_native.abi3.so
|
||||
fi
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -8,10 +8,9 @@ The following caching mechanisms are supported:
|
|||
2. **RedisSemanticCache**
|
||||
3. **QdrantSemanticCache**
|
||||
4. **InMemoryCache**
|
||||
5. **DiskCache**
|
||||
6. **S3Cache**
|
||||
7. **AzureBlobCache**
|
||||
8. **DualCache** (updates both Redis and an in-memory cache simultaneously)
|
||||
5. **S3Cache**
|
||||
6. **AzureBlobCache**
|
||||
7. **DualCache** (updates both Redis and an in-memory cache simultaneously)
|
||||
|
||||
## Folder Structure
|
||||
|
||||
|
|
@ -20,7 +19,6 @@ litellm/caching/
|
|||
├── base_cache.py
|
||||
├── caching.py
|
||||
├── caching_handler.py
|
||||
├── disk_cache.py
|
||||
├── dual_cache.py
|
||||
├── in_memory_cache.py
|
||||
├── qdrant_semantic_cache.py
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from .azure_blob_cache import AzureBlobCache
|
||||
from .caching import Cache, LiteLLMCacheType
|
||||
from .disk_cache import DiskCache
|
||||
from .dual_cache import DualCache
|
||||
from .gcs_cache import GCSCache
|
||||
from .in_memory_cache import InMemoryCache
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ from litellm.types.utils import EmbeddingResponse, is_litellm_owned_kwarg
|
|||
|
||||
from .azure_blob_cache import AzureBlobCache
|
||||
from .base_cache import BaseCache
|
||||
from .disk_cache import DiskCache
|
||||
from .dual_cache import DualCache # noqa: F401 # re-exported, callers import DualCache from litellm.caching.caching
|
||||
from .gcs_cache import GCSCache
|
||||
from .in_memory_cache import InMemoryCache
|
||||
|
|
@ -132,7 +131,6 @@ class Cache:
|
|||
valkey_semantic_cache_index_name: str | None = None,
|
||||
redis_flush_size: int | None = None,
|
||||
redis_startup_nodes: list | None = None,
|
||||
disk_cache_dir: str | None = None,
|
||||
qdrant_api_base: str | None = None,
|
||||
qdrant_api_key: str | None = None,
|
||||
qdrant_collection_name: str | None = None,
|
||||
|
|
@ -153,7 +151,7 @@ class Cache:
|
|||
Initializes the cache based on the given type.
|
||||
|
||||
Args:
|
||||
type (str, optional): The type of cache to initialize. Can be "local", "redis", "redis-semantic", "qdrant-semantic", "s3" or "disk". Defaults to "local".
|
||||
type (str, optional): The type of cache to initialize. Can be "local", "redis", "redis-semantic", "qdrant-semantic" or "s3". Defaults to "local".
|
||||
|
||||
# Redis Cache Args
|
||||
host (str, optional): The host address for the Redis cache. Required if type is "redis".
|
||||
|
|
@ -174,9 +172,6 @@ class Cache:
|
|||
semantic_cache_scope (str, optional): "key" isolates semantic-cache buckets per key/team/org. "end_user" additionally isolates per end user (falls back to the key scope when the request carries no end-user id). Defaults to "key".
|
||||
max_messages (int, optional): Requests with more `messages` (or Responses API `input` items) than this are neither looked up nor stored, so long agent conversations never serve or create a cache entry. None disables the limit. Defaults to 4.
|
||||
|
||||
# Disk Cache Args
|
||||
disk_cache_dir (str, optional): The directory for the disk cache. Defaults to None.
|
||||
|
||||
# S3 Cache Args
|
||||
s3_bucket_name (str, optional): The bucket name for the s3 cache. Defaults to None.
|
||||
s3_region_name (str, optional): The region name for the s3 cache. Defaults to None.
|
||||
|
|
@ -306,8 +301,9 @@ class Cache:
|
|||
account_url=azure_account_url,
|
||||
container=azure_blob_container,
|
||||
)
|
||||
elif type == LiteLLMCacheType.DISK:
|
||||
self.cache = DiskCache(disk_cache_dir=disk_cache_dir)
|
||||
else:
|
||||
supported_types: Final = ", ".join(member.value for member in LiteLLMCacheType)
|
||||
raise ValueError(f"Unsupported cache type {type!r}. Supported types: {supported_types}")
|
||||
if "cache" not in litellm.input_callback:
|
||||
litellm.input_callback.append("cache")
|
||||
if "cache" not in litellm.success_callback:
|
||||
|
|
@ -1028,7 +1024,7 @@ def enable_cache(
|
|||
Enable cache with the specified configuration.
|
||||
|
||||
Args:
|
||||
type (Optional[Literal["local", "redis", "s3", "disk"]]): The type of cache to enable. Defaults to "local".
|
||||
type (Optional[Literal["local", "redis", "s3"]]): The type of cache to enable. Defaults to "local".
|
||||
host (Optional[str]): The host address of the cache server. Defaults to None.
|
||||
port (Optional[str]): The port number of the cache server. Defaults to None.
|
||||
password (Optional[str]): The password for the cache server. Defaults to None.
|
||||
|
|
@ -1075,7 +1071,7 @@ def update_cache(
|
|||
Update the cache for LiteLLM.
|
||||
|
||||
Args:
|
||||
type (Optional[Literal["local", "redis", "s3", "disk"]]): The type of cache. Defaults to "local".
|
||||
type (Optional[Literal["local", "redis", "s3"]]): The type of cache. Defaults to "local".
|
||||
host (Optional[str]): The host of the cache. Defaults to None.
|
||||
port (Optional[str]): The port of the cache. Defaults to None.
|
||||
password (Optional[str]): The password for the cache. Defaults to None.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ This file is a wrapper around caching.py
|
|||
|
||||
This class is used to handle caching logic specific for LLM API requests (completion / embedding / text_completion / transcription etc)
|
||||
|
||||
It utilizes the (RedisCache, s3Cache, RedisSemanticCache, QdrantSemanticCache, InMemoryCache, DiskCache) based on what the user has setup
|
||||
It utilizes the (RedisCache, s3Cache, RedisSemanticCache, QdrantSemanticCache, InMemoryCache) based on what the user has setup
|
||||
|
||||
In each method it will call the appropriate method from caching.py
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
import json
|
||||
from typing import TYPE_CHECKING, Any, Final
|
||||
|
||||
from pydantic import TypeAdapter
|
||||
|
||||
from .base_cache import BaseCache
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opentelemetry.trace import Span as _Span
|
||||
|
||||
Span = _Span
|
||||
else:
|
||||
Span = Any
|
||||
|
||||
_DECODED_DISK_VALUE: Final = TypeAdapter(object)
|
||||
|
||||
|
||||
class DiskCache(BaseCache):
|
||||
def __init__(self, disk_cache_dir: str | None = None):
|
||||
try:
|
||||
import diskcache as dc
|
||||
except ModuleNotFoundError as e:
|
||||
raise ModuleNotFoundError("Please install litellm with `litellm[caching]` to use disk caching.") from e
|
||||
|
||||
# if users don't provider one, use the default litellm cache
|
||||
if disk_cache_dir is None:
|
||||
self.disk_cache = dc.Cache(".litellm_cache")
|
||||
else:
|
||||
self.disk_cache = dc.Cache(disk_cache_dir)
|
||||
|
||||
def set_cache(self, key, value, **kwargs):
|
||||
if "ttl" in kwargs:
|
||||
self.disk_cache.set(key, value, expire=kwargs["ttl"])
|
||||
else:
|
||||
self.disk_cache.set(key, value)
|
||||
|
||||
async def async_set_cache(self, key, value, **kwargs):
|
||||
self.set_cache(key=key, value=value, **kwargs)
|
||||
|
||||
async def async_set_cache_pipeline(self, cache_list, **kwargs):
|
||||
for cache_key, cache_value in cache_list:
|
||||
if "ttl" in kwargs:
|
||||
self.set_cache(key=cache_key, value=cache_value, ttl=kwargs["ttl"])
|
||||
else:
|
||||
self.set_cache(key=cache_key, value=cache_value)
|
||||
|
||||
def get_cache(self, key, **kwargs):
|
||||
original_cached_response: Final = self.disk_cache.get(key)
|
||||
if original_cached_response:
|
||||
try:
|
||||
cached_response = _DECODED_DISK_VALUE.validate_python(json.loads(original_cached_response))
|
||||
except Exception:
|
||||
cached_response = original_cached_response
|
||||
return cached_response
|
||||
return None
|
||||
|
||||
def batch_get_cache(self, keys: list, **kwargs):
|
||||
return_val: Final = []
|
||||
for k in keys:
|
||||
val = self.get_cache(key=k, **kwargs)
|
||||
return_val.append(val)
|
||||
return return_val
|
||||
|
||||
def increment_cache(self, key, value: int, **kwargs) -> int:
|
||||
with self.disk_cache.transact():
|
||||
cached_value: Final = self.get_cache(key=key)
|
||||
init_value: Final = cached_value if isinstance(cached_value, int) else 0
|
||||
new_value: Final = init_value + value
|
||||
self.set_cache(key, new_value, **kwargs)
|
||||
return new_value
|
||||
|
||||
async def async_get_cache(self, key, **kwargs):
|
||||
return self.get_cache(key=key, **kwargs)
|
||||
|
||||
async def async_batch_get_cache(self, keys: list, **kwargs):
|
||||
return_val: Final = []
|
||||
for k in keys:
|
||||
val = self.get_cache(key=k, **kwargs)
|
||||
return_val.append(val)
|
||||
return return_val
|
||||
|
||||
async def async_increment(self, key, value: int, **kwargs) -> int:
|
||||
return self.increment_cache(key=key, value=value, **kwargs)
|
||||
|
||||
def flush_cache(self):
|
||||
self.disk_cache.clear()
|
||||
|
||||
async def disconnect(self):
|
||||
pass
|
||||
|
||||
def delete_cache(self, key):
|
||||
self.disk_cache.pop(key)
|
||||
|
|
@ -1383,7 +1383,7 @@ class Router:
|
|||
self.deployment_names: list = [] # names of models under litellm_params. ex. azure/chatgpt-v-2
|
||||
self.deployment_latency_map = {}
|
||||
### CACHING ###
|
||||
cache_type: Literal["local", "redis", "redis-semantic", "s3", "disk"] = "local" # default to an in-memory cache
|
||||
cache_type: Literal["local", "redis", "redis-semantic", "s3"] = "local" # default to an in-memory cache
|
||||
redis_cache = None
|
||||
cache_config: Final[dict[str, Any]] = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ class LiteLLMCacheType(str, Enum):
|
|||
REDIS_SEMANTIC = "redis-semantic"
|
||||
VALKEY_SEMANTIC = "valkey-semantic"
|
||||
S3 = "s3"
|
||||
DISK = "disk"
|
||||
QDRANT_SEMANTIC = "qdrant-semantic"
|
||||
AZURE_BLOB = "azure-blob"
|
||||
GCS = "gcs"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
[[IgnoredVulns]]
|
||||
id = "GHSA-w8v5-vhqr-4h9v"
|
||||
ignoreUntil = 2026-11-01
|
||||
reason = "diskcache has no fixed release published; remove this entry once one exists"
|
||||
|
||||
[[IgnoredVulns]]
|
||||
id = "GHSA-v4x8-3wr5-3wq8"
|
||||
ignoreUntil = 2026-11-20
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ utils = [
|
|||
# Not in Docker or PyPI proxy extra.
|
||||
"numpydoc>=1.8.0,<2.0",
|
||||
]
|
||||
caching = ["diskcache>=5.6.3,<6.0"]
|
||||
mcp = ["mcp>=2.3.0,<3", "httpx2>=2.10.0,<3", "pydantic>=2.12.0,<3"]
|
||||
# Driver for the MongoDB Atlas vector store; Atlas Vector Search has no HTTP query API.
|
||||
# The floor is 4.9 because that is the release AsyncMongoClient landed in.
|
||||
|
|
|
|||
|
|
@ -250,6 +250,13 @@ def test_semantic_cache_key_reads_tenant_identity_from_litellm_metadata():
|
|||
assert key_a == key_a_in_litellm_params
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cache_type", ["disk", "not-a-cache"])
|
||||
def test_cache_rejects_unsupported_type(cache_type: str) -> None:
|
||||
cache_params: Final = {"type": cache_type}
|
||||
with pytest.raises(ValueError, match=f"Unsupported cache type '{cache_type}'. Supported types: local, redis,"):
|
||||
Cache(**cache_params)
|
||||
|
||||
|
||||
def test_semantic_cache_scope_rejects_unknown_value():
|
||||
with pytest.raises(ValueError, match="'team' is not a valid SemanticCacheScope"):
|
||||
_semantic_cache(semantic_cache_scope="team")
|
||||
|
|
|
|||
|
|
@ -1,158 +0,0 @@
|
|||
import threading
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
|
||||
pytest.importorskip("diskcache")
|
||||
|
||||
from litellm.caching.disk_cache import DiskCache
|
||||
from tests._wait_helpers import await_until
|
||||
|
||||
|
||||
class _SlowInt(int):
|
||||
def __add__(self, value: int) -> "_SlowInt":
|
||||
time.sleep(0.05)
|
||||
return _SlowInt(int(self) + value)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cache(tmp_path):
|
||||
return DiskCache(disk_cache_dir=str(tmp_path))
|
||||
|
||||
|
||||
def test_increment_cache_starts_from_zero_when_key_missing(cache):
|
||||
assert cache.increment_cache("counter", 3) == 3
|
||||
assert cache.get_cache("counter") == 3
|
||||
|
||||
|
||||
def test_increment_cache_adds_to_existing_int(cache):
|
||||
cache.set_cache("counter", 7)
|
||||
assert cache.increment_cache("counter", 5) == 12
|
||||
assert cache.get_cache("counter") == 12
|
||||
|
||||
|
||||
def test_increment_cache_treats_non_int_cached_value_as_zero(cache):
|
||||
cache.set_cache("counter", "not-a-number")
|
||||
assert cache.increment_cache("counter", 4) == 4
|
||||
assert cache.get_cache("counter") == 4
|
||||
|
||||
|
||||
def test_increment_cache_is_atomic_under_thread_concurrency(cache):
|
||||
seed = 1000
|
||||
cache.set_cache("counter", _SlowInt(seed))
|
||||
thread_count = 8
|
||||
barrier = threading.Barrier(thread_count)
|
||||
|
||||
def increment(_: int) -> int:
|
||||
barrier.wait()
|
||||
return cache.increment_cache("counter", 1)
|
||||
|
||||
with ThreadPoolExecutor(max_workers=thread_count) as executor:
|
||||
tuple(executor.map(increment, range(thread_count)))
|
||||
|
||||
assert cache.get_cache("counter") == seed + thread_count
|
||||
|
||||
|
||||
async def test_async_increment_starts_from_zero_when_key_missing(cache):
|
||||
assert await cache.async_increment("counter", 2) == 2
|
||||
|
||||
|
||||
async def test_async_increment_adds_to_existing_int(cache):
|
||||
await cache.async_set_cache("counter", 10)
|
||||
assert await cache.async_increment("counter", 5) == 15
|
||||
|
||||
|
||||
async def test_async_increment_treats_non_int_cached_value_as_zero(cache):
|
||||
await cache.async_set_cache("counter", "corrupt")
|
||||
assert await cache.async_increment("counter", 9) == 9
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def disk_cache(tmp_path):
|
||||
import litellm
|
||||
from litellm.caching import Cache
|
||||
|
||||
litellm.cache = Cache(type="disk", disk_cache_dir=str(tmp_path))
|
||||
yield litellm.cache
|
||||
litellm.cache = None
|
||||
|
||||
|
||||
COMPLETION_MESSAGES = [{"role": "user", "content": "write a one sentence poem about: disk-cache-unit-key"}]
|
||||
|
||||
|
||||
def test_completion_is_served_from_disk_cache_until_params_change(disk_cache):
|
||||
import litellm
|
||||
|
||||
first = litellm.completion(
|
||||
"gpt-3.5-turbo", messages=COMPLETION_MESSAGES, caching=True, max_tokens=20, mock_response="first"
|
||||
)
|
||||
repeat = litellm.completion(
|
||||
"gpt-3.5-turbo", messages=COMPLETION_MESSAGES, caching=True, max_tokens=20, mock_response="second"
|
||||
)
|
||||
changed = litellm.completion(
|
||||
"gpt-3.5-turbo", messages=COMPLETION_MESSAGES, caching=True, temperature=0.5, mock_response="third"
|
||||
)
|
||||
|
||||
assert (repeat.choices[0].message.content, repeat.id, repeat.created) == (
|
||||
first.choices[0].message.content,
|
||||
first.id,
|
||||
first.created,
|
||||
)
|
||||
assert changed.choices[0].message.content == "third"
|
||||
|
||||
|
||||
async def test_async_completion_is_served_from_disk_cache_until_params_change(disk_cache):
|
||||
import litellm
|
||||
|
||||
first = await litellm.acompletion(
|
||||
"gpt-3.5-turbo", messages=COMPLETION_MESSAGES, caching=True, max_tokens=20, mock_response="first"
|
||||
)
|
||||
await await_until(lambda: len(disk_cache.cache.disk_cache) == 1, message="the first completion is cached")
|
||||
repeat = await litellm.acompletion(
|
||||
"gpt-3.5-turbo", messages=COMPLETION_MESSAGES, caching=True, max_tokens=20, mock_response="second"
|
||||
)
|
||||
changed = await litellm.acompletion(
|
||||
"gpt-3.5-turbo", messages=COMPLETION_MESSAGES, caching=True, temperature=0.5, mock_response="third"
|
||||
)
|
||||
|
||||
assert (repeat.choices[0].message.content, repeat.id, repeat.created) == (
|
||||
first.choices[0].message.content,
|
||||
first.id,
|
||||
first.created,
|
||||
)
|
||||
assert changed.choices[0].message.content == "third"
|
||||
|
||||
|
||||
async def test_embedding_is_served_from_disk_cache_until_params_change(disk_cache, respx_mock, monkeypatch):
|
||||
import httpx
|
||||
|
||||
import litellm
|
||||
|
||||
monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)
|
||||
input_text = ["hello disk-embedding-unit-key"]
|
||||
embeddings_route = respx_mock.post("https://api.openai.com/v1/embeddings").mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"object": "list",
|
||||
"data": [{"object": "embedding", "index": 0, "embedding": [0.1, 0.2, 0.3]}],
|
||||
"model": "text-embedding-ada-002",
|
||||
"usage": {"prompt_tokens": 2, "total_tokens": 2},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
await litellm.aembedding("openai/text-embedding-ada-002", input=input_text, caching=True, api_key="sk-unit")
|
||||
await await_until(lambda: len(disk_cache.cache.disk_cache) == 1, message="the first embedding is cached")
|
||||
cached = await litellm.aembedding(
|
||||
"openai/text-embedding-ada-002", input=input_text, caching=True, api_key="sk-unit"
|
||||
)
|
||||
assert cached._hidden_params["cache_hit"] is True
|
||||
assert cached.data[0]["embedding"] == [0.1, 0.2, 0.3]
|
||||
assert embeddings_route.call_count == 1
|
||||
|
||||
await litellm.aembedding(
|
||||
"openai/text-embedding-ada-002", input=input_text, caching=True, user="charlie", api_key="sk-unit"
|
||||
)
|
||||
assert embeddings_route.call_count == 2
|
||||
|
|
@ -1656,7 +1656,7 @@ def test_ProxyConfig__init_cache_sets_litellm_cache(monkeypatch):
|
|||
|
||||
def test_ProxyConfig__init_cache_invalid_params_raises():
|
||||
pc = ProxyConfig()
|
||||
with pytest.raises(AttributeError):
|
||||
with pytest.raises(ValueError, match="Unsupported cache type 'this-cache-type-does-not-exist'"):
|
||||
pc._init_cache(cache_params={"type": "this-cache-type-does-not-exist"})
|
||||
|
||||
|
||||
|
|
|
|||
15
uv.lock
generated
15
uv.lock
generated
|
|
@ -1952,15 +1952,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diskcache"
|
||||
version = "5.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "distro"
|
||||
version = "1.9.0"
|
||||
|
|
@ -4992,9 +4983,6 @@ dependencies = [
|
|||
bedrock-realtime = [
|
||||
{ name = "aws-sdk-bedrock-runtime", extra = ["awscrt"], marker = "python_full_version >= '3.12'" },
|
||||
]
|
||||
caching = [
|
||||
{ name = "diskcache" },
|
||||
]
|
||||
cli = [
|
||||
{ name = "inquirerpy" },
|
||||
{ name = "keyring" },
|
||||
|
|
@ -5247,7 +5235,6 @@ requires-dist = [
|
|||
{ name = "cryptography", marker = "extra == 'proxy'", specifier = ">=49.0.0,<51.0" },
|
||||
{ name = "ddtrace", marker = "extra == 'proxy-runtime'", specifier = ">=4.8.2,<5.0" },
|
||||
{ name = "detect-secrets", marker = "extra == 'proxy-runtime'", specifier = ">=1.5.0,<2.0" },
|
||||
{ name = "diskcache", marker = "extra == 'caching'", specifier = ">=5.6.3,<6.0" },
|
||||
{ name = "expression", marker = "extra == 'proxy'", specifier = ">=5.6.0,<6.0" },
|
||||
{ name = "fastapi", marker = "extra == 'proxy'", specifier = ">=0.136.3,<1.0" },
|
||||
{ name = "fastapi-sso", marker = "extra == 'proxy'", specifier = ">=0.19.0,<1.0" },
|
||||
|
|
@ -5340,7 +5327,7 @@ requires-dist = [
|
|||
{ name = "uvloop", marker = "sys_platform != 'win32' and extra == 'proxy'", specifier = ">=0.22.1,<1.0" },
|
||||
{ name = "websockets", marker = "extra == 'proxy'", specifier = ">=15.0.1,<16.0" },
|
||||
]
|
||||
provides-extras = ["proxy", "cli", "extra-proxy", "utils", "caching", "mcp", "saml", "semantic-router", "mlflow", "grpc", "stt-vertex-chirp", "stt-nvidia-riva", "google", "bedrock-realtime", "proxy-runtime"]
|
||||
provides-extras = ["proxy", "cli", "extra-proxy", "utils", "mcp", "saml", "semantic-router", "mlflow", "grpc", "stt-vertex-chirp", "stt-nvidia-riva", "google", "bedrock-realtime", "proxy-runtime"]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
admin-mcp = [{ name = "litellm-admin-mcp", marker = "python_full_version >= '3.12'", url = "https://github.com/BerriAI/liteadmin-mcp/archive/d35ec9c19c117d4c50cc1eccf6ce1296aac25a1a.tar.gz" }]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue